<!DOCTYPE html>



  


<html class="theme-next muse use-motion" lang="zh-Hans">
<head>
  <meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
<meta name="theme-color" content="#222">



  
  
    
    
  <script src="/lib/pace/pace.min.js?v=1.0.2"></script>
  <link href="/lib/pace/pace-theme-center-minimal.min.css?v=1.0.2" rel="stylesheet">







<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
















  
  
  <link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />







<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />

<link href="/css/main.css?v=5.1.3" rel="stylesheet" type="text/css" />


  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon.png?v=5.1.3">


  <link rel="icon" type="image/png" sizes="32x32" href="http://7xqdz8.com1.z0.glb.clouddn.com/avatar.png?v=5.1.3">


  <link rel="icon" type="image/png" sizes="16x16" href="http://7xqdz8.com1.z0.glb.clouddn.com/avatar.png?v=5.1.3">


  <link rel="mask-icon" href="/images/logo.svg?v=5.1.3" color="#222">





  <meta name="keywords" content="Android,源码分析," />










<meta name="description" content="0. 介绍此文将对Github上lguipeng大神所开发的 极简笔记 v2.0 (点我下载源码)代码进行分析学习。通过此文你将学到:

应用源码的研读方法
MVP架构模式
Application的应用
Degger2依赖注入框架
搜索控件的使用
ButterKnife库的使用
Material主题
RecyclerView等新控件的用法
Lambda表达式
Java自定义注解
aFinal框架">
<meta property="og:type" content="article">
<meta property="og:title" content="《极简笔记》源码分析">
<meta property="og:url" content="/2016/04/08/Notes/index.html">
<meta property="og:site_name" content="一路前行">
<meta property="og:description" content="0. 介绍此文将对Github上lguipeng大神所开发的 极简笔记 v2.0 (点我下载源码)代码进行分析学习。通过此文你将学到:

应用源码的研读方法
MVP架构模式
Application的应用
Degger2依赖注入框架
搜索控件的使用
ButterKnife库的使用
Material主题
RecyclerView等新控件的用法
Lambda表达式
Java自定义注解
aFinal框架">
<meta property="og:image" content="http://7xqdz8.com1.z0.glb.clouddn.com/160408Project.png">
<meta property="og:image" content="http://7xqdz8.com1.z0.glb.clouddn.com/160409sc_main.png">
<meta property="og:image" content="http://7xqdz8.com1.z0.glb.clouddn.com/160409ButterKnife.png">
<meta property="og:image" content="http://7xqdz8.com1.z0.glb.clouddn.com/160410none.png">
<meta property="og:image" content="http://7xqdz8.com1.z0.glb.clouddn.com/160410single.png">
<meta property="og:image" content="http://7xqdz8.com1.z0.glb.clouddn.com/160411class.png">
<meta property="og:image" content="http://7xqdz8.com1.z0.glb.clouddn.com/160411scrim.png">
<meta property="og:image" content="http://7xqdz8.com1.z0.glb.clouddn.com/160413drawright.png">
<meta property="og:image" content="http://7xqdz8.com1.z0.glb.clouddn.com/160413schedulers.png">
<meta property="og:image" content="http://7xqdz8.com1.z0.glb.clouddn.com/160418sc_new_note.png">
<meta property="og:image" content="http://7xqdz8.com1.z0.glb.clouddn.com/160424layout.png">
<meta property="og:image" content="http://7xqdz8.com1.z0.glb.clouddn.com/160424setting.png">
<meta property="og:image" content="http://7xqdz8.com1.z0.glb.clouddn.com/160424theme.png">
<meta property="og:image" content="http://7xqdz8.com1.z0.glb.clouddn.com/160424about.png">
<meta property="og:image" content="http://7xqdz8.com1.z0.glb.clouddn.com/160424share.png">
<meta property="og:updated_time" content="2016-04-24T13:40:51.783Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="《极简笔记》源码分析">
<meta name="twitter:description" content="0. 介绍此文将对Github上lguipeng大神所开发的 极简笔记 v2.0 (点我下载源码)代码进行分析学习。通过此文你将学到:

应用源码的研读方法
MVP架构模式
Application的应用
Degger2依赖注入框架
搜索控件的使用
ButterKnife库的使用
Material主题
RecyclerView等新控件的用法
Lambda表达式
Java自定义注解
aFinal框架">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/',
    scheme: 'Muse',
    version: '5.1.3',
    sidebar: {"position":"left","display":"post","offset":12,"b2t":false,"scrollpercent":false,"onmobile":false},
    fancybox: true,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    duoshuo: {
      userId: '0',
      author: '博主'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="/2016/04/08/Notes/"/>





  <title>《极简笔记》源码分析 | 一路前行</title>
  





  <script type="text/javascript">
    var _hmt = _hmt || [];
    (function() {
      var hm = document.createElement("script");
      hm.src = "https://hm.baidu.com/hm.js?8193f7e44c62cdda245d5f109196c830";
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(hm, s);
    })();
  </script>




</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">

  
  
    
  

  <div class="container sidebar-position-left page-post-detail">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/"  class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">一路前行</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <p class="site-subtitle">Always believe that some thing wonderful is about to happen.</p>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br />
            
            首页
          </a>
        </li>
      
        
        <li class="menu-item menu-item-categories">
          <a href="/categories/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-th"></i> <br />
            
            分类
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/archives/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br />
            
            归档
          </a>
        </li>
      
        
        <li class="menu-item menu-item-about">
          <a href="/about/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-user"></i> <br />
            
            关于
          </a>
        </li>
      

      
    </ul>
  

  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="/2016/04/08/Notes/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="Voyager">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="http://7xqdz8.com1.z0.glb.clouddn.com/avatar.png">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="一路前行">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">《极简笔记》源码分析</h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2016-04-08T18:00:00+08:00">
                2016-04-08
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Android/" itemprop="url" rel="index">
                    <span itemprop="name">Android</span>
                  </a>
                </span>

                
                
                  ， 
                
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Android/源码分析/" itemprop="url" rel="index">
                    <span itemprop="name">源码分析</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        <h1 id="0-__u4ECB_u7ECD"><a href="#0-__u4ECB_u7ECD" class="headerlink" title="0. 介绍"></a>0. 介绍</h1><p>此文将对Github上<a href="https://github.com/lguipeng" target="_blank" rel="external">lguipeng</a>大神所开发的 <code>极简笔记 v2.0</code> (<a href="https://github.com/a-voyager/Notes" target="_blank" rel="external">点我下载源码</a>)代码进行分析学习。<br>通过此文你将学到:</p>
<ul>
<li>应用源码的研读方法</li>
<li>MVP架构模式</li>
<li>Application的应用</li>
<li>Degger2依赖注入框架</li>
<li>搜索控件的使用</li>
<li>ButterKnife库的使用</li>
<li>Material主题</li>
<li>RecyclerView等新控件的用法</li>
<li>Lambda表达式</li>
<li>Java自定义注解</li>
<li>aFinal框架</li>
<li>RxJava框架</li>
<li>EventBus消息框架</li>
<li>布局文件常用技巧</li>
<li>PreferenceFragment</li>
<li>动态申请权限</li>
</ul>
<a id="more"></a>
<h1 id="1-_Manifest_u5165_u624B"><a href="#1-_Manifest_u5165_u624B" class="headerlink" title="1. Manifest入手"></a>1. Manifest入手</h1><h2 id="1-1__u6743_u9650"><a href="#1-1__u6743_u9650" class="headerlink" title="1.1 权限"></a>1.1 权限</h2><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">uses-permission</span> <span class="attribute">android:name</span>=<span class="value">"android.permission.INTERNET"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">uses-permission</span> <span class="attribute">android:name</span>=<span class="value">"android.permission.ACCESS_WIFI_STATE"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">uses-permission</span> <span class="attribute">android:name</span>=<span class="value">"android.permission.ACCESS_NETWORK_STATE"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">uses-permission</span> <span class="attribute">android:name</span>=<span class="value">"android.permission.READ_PHONE_STATE"</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">uses-permission</span> <span class="attribute">android:name</span>=<span class="value">"android.permission.WRITE_EXTERNAL_STORAGE"</span>/&gt;</span></span><br></pre></td></tr></table></figure>
<p>声明了网络与储存读写相关权限，至于网络权限笔者猜测应该是用于印象笔记的同步吧。</p>
<h2 id="1-2_Application_u5C42"><a href="#1-2_Application_u5C42" class="headerlink" title="1.2 Application层"></a>1.2 Application层</h2><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">android:name=".App"</span><br></pre></td></tr></table></figure>
<p><img src="http://7xqdz8.com1.z0.glb.clouddn.com/160408Project.png" alt="项目结构"></p>
<p>在Application层发现了一个奇怪的属性，然后又发现项目结构目录中有个继承自Application的类，顿时疑惑。经查阅后又联想到包建强的《App研发录》中提到彻底结束安卓程序进程需要用到继承Application的类来记录已经打开的Activity，然后统一结束它们，如代码所示:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">App</span> <span class="keyword">extends</span> <span class="title">Application</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">public</span> List&lt;Activity&gt; activities=<span class="keyword">new</span> ArrayList&lt;Activity&gt;();</span><br><span class="line">	</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>Manifest进行注册:<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">application</span></span><br><span class="line">        <span class="attribute">android:icon</span>=<span class="value">"@drawable/icon"</span></span><br><span class="line">        <span class="attribute">android:label</span>=<span class="value">"@string/app_name"</span></span><br><span class="line">        <span class="attribute">android:name</span>=<span class="value">".App"</span> &gt;</span></span><br></pre></td></tr></table></figure></p>
<p>每个Activity中的做法如下：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//首先：onCreate（）方法里边：</span></span><br><span class="line">    App app = (App) getApplicationContext();<span class="comment">// 获取应用程序全局的实例引用</span></span><br><span class="line">    app.activities.add(<span class="keyword">this</span>); <span class="comment">// 把当前Activity放入集合中</span></span><br><span class="line">  </span><br><span class="line"><span class="comment">//然后：onDestroy()方法里边做法：</span></span><br><span class="line">     <span class="annotation">@Override</span></span><br><span class="line">     <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onDestroy</span><span class="params">()</span> </span>&#123;</span><br><span class="line">	<span class="keyword">super</span>.onDestroy();</span><br><span class="line">	App app = (App) getApplication();<span class="comment">// 获取应用程序全局的实例引用</span></span><br><span class="line">	app.activities.remove(<span class="keyword">this</span>); <span class="comment">// 把当前Activity从集合中移除</span></span><br><span class="line">     &#125;</span><br><span class="line"><span class="comment">//最后:在程序中需要结束时的做法：</span></span><br><span class="line">    List&lt;Activity&gt; activities = app.activities;</span><br><span class="line">    <span class="keyword">for</span> (Activity act : activities) &#123;</span><br><span class="line">	act.finish();<span class="comment">// 显式结束</span></span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure></p>
<p>我想此处亦是同样原理。</p>
<blockquote>
<p>补充Application相关知识点：</p>
<ul>
<li>创建一个类继承Application并在manifest的application标签中进行注册</li>
<li>生命周期等于这个程序的生命周期</li>
<li>通常用于数据传递、数据共享、数据缓存等操作</li>
<li>onTerminate() 当终止应用程序对象时调用 onLowMemory() 当后台程序已经终止资源还匮乏时会调用</li>
</ul>
</blockquote>
<h3 id="1-2-1__u63A2_u7D22_u7EE7_u627F_u81EAApplication_u7684App_u7C7B"><a href="#1-2-1__u63A2_u7D22_u7EE7_u627F_u81EAApplication_u7684App_u7C7B" class="headerlink" title="1.2.1 探索继承自Application的App类"></a>1.2.1 探索继承自Application的App类</h3><p>类中定义了以下方法:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">initializeInjector</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    mAppComponent = DaggerAppComponent.builder()</span><br><span class="line">            .appModule(<span class="keyword">new</span> AppModule(<span class="keyword">this</span>))</span><br><span class="line">            .build();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>通过DaggerAppComponent可以发现使用了Dagger2库，那么Dagger库又是什么呢？继续探索…</p>
<h3 id="1-2-1-1_Dagger2_u4ECB_u7ECD"><a href="#1-2-1-1_Dagger2_u4ECB_u7ECD" class="headerlink" title="1.2.1.1 Dagger2介绍"></a>1.2.1.1 Dagger2介绍</h3><p>在此之前，需要先了解依赖注入，在本人看来其实就是低级类对高级类的依赖关系，它有以下好处: </p>
<ul>
<li>依赖的注入和配置独立于组件之外</li>
<li>因为对象是在一个独立、不耦合的地方初始化，所以当注入抽象方法的时候，我们只需要修改对象的实现方法，而不用大改代码库</li>
<li>依赖可以注入到一个组件中：我们可以注入这些依赖的模拟实现，这样使得测试更加简单<br>而Dagger2就是Google基于java的依赖注入标准维护的一个库。</li>
</ul>
<h3 id="1-2-1-1_Dagger2_u7684_u4F7F_u7528"><a href="#1-2-1-1_Dagger2_u7684_u4F7F_u7528" class="headerlink" title="1.2.1.1 Dagger2的使用"></a>1.2.1.1 Dagger2的使用</h3><p><strong>第一步: 添加编译和运行库</strong><br><figure class="highlight gradle"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">dependencies</span> &#123;</span><br><span class="line">  apt <span class="string">'com.google.dagger:dagger-compiler:2.0'</span></span><br><span class="line">  <span class="keyword">compile</span> <span class="string">'com.google.dagger:dagger:2.0'</span></span><br><span class="line">  ...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p><strong>第二步: 构建依赖</strong><br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Module</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ActivityModule</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Provides</span> <span class="function">UserModel <span class="title">provideUserModel</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> UserModel();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p><strong>第三步: 构建Injector</strong><br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Component</span>(modules = ActivityModule.class)</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">ActivityComponent</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">inject</span><span class="params">(MainActivity activity)</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p><strong>第三步: 完成依赖注入</strong><br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MainActivity</span> <span class="keyword">extends</span> <span class="title">ActionBarActivity</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> ActivityComponent mActivityComponent;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Inject</span> UserModel userModel;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle savedInstanceState)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">super</span>.onCreate(savedInstanceState);</span><br><span class="line">        setContentView(R.layout.activity_main);</span><br><span class="line">        mActivityComponent = DaggerActivityComponent.builder().activityModule(<span class="keyword">new</span> ActivityModule()).build();</span><br><span class="line">        mActivityComponent.inject(<span class="keyword">this</span>);</span><br><span class="line">        ((TextView) findViewById(R.id.user_desc_line)).setText(userModel.id + <span class="string">"\n"</span> + userModel.name + <span class="string">"\n"</span> + userModel.gender);</span><br><span class="line">    &#125;</span><br><span class="line">    ...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h2 id="1-3_Activity_u5C42"><a href="#1-3_Activity_u5C42" class="headerlink" title="1.3 Activity层"></a>1.3 Activity层</h2><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">activity</span></span><br><span class="line">    <span class="attribute">android:name</span>=<span class="value">".ui.MainActivity"</span></span><br><span class="line">    <span class="attribute">android:launchMode</span>=<span class="value">"singleTop"</span></span><br><span class="line">    <span class="attribute">android:windowSoftInputMode</span>=<span class="value">"adjustResize|stateHidden"</span></span><br><span class="line">    <span class="attribute">android:screenOrientation</span>=<span class="value">"portrait"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">meta-data</span></span><br><span class="line">        <span class="attribute">android:name</span>=<span class="value">"android.app.searchable"</span></span><br><span class="line">        <span class="attribute">android:resource</span>=<span class="value">"@xml/searchable"</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">intent-filter</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">action</span> <span class="attribute">android:name</span>=<span class="value">"android.intent.action.MAIN"</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">category</span> <span class="attribute">android:name</span>=<span class="value">"android.intent.category.LAUNCHER"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="title">intent-filter</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">intent-filter</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">action</span> <span class="attribute">android:name</span>=<span class="value">"android.intent.action.SEARCH"</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="title">intent-filter</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>由<intent-filter>标签里的内容可以看出该Activity是程序启动的主Activity，如图:<br><img src="http://7xqdz8.com1.z0.glb.clouddn.com/160409sc_main.png" alt="主Activity界面"><br>此外，还有一点值得注意:</intent-filter></p>
<h2 id="1-3-1__u641C_u7D22_u529F_u80FD_u7684_u4F7F_u7528_u65B9_u6CD5"><a href="#1-3-1__u641C_u7D22_u529F_u80FD_u7684_u4F7F_u7528_u65B9_u6CD5" class="headerlink" title="1.3.1 搜索功能的使用方法"></a>1.3.1 搜索功能的使用方法</h2><p>搜索有两种实现方式，默认搜索框(比如Toolbar上面的)和搜索控件(可以在Layout里面声明的SearchView)，一般采用默认的搜索框方式即可，此处也只简单讲讲此方式，如要了解更多可以去阅读官方文档的<a href="http://developer.android.com/guide/topics/search/search-dialog.html" target="_blank" rel="external">创建搜索界面</a></p>
<h3 id="1-3-1-1__u521B_u5EFA_u641C_u7D22_u914D_u7F6E_u6587_u4EF6"><a href="#1-3-1-1__u521B_u5EFA_u641C_u7D22_u914D_u7F6E_u6587_u4EF6" class="headerlink" title="1.3.1.1 创建搜索配置文件"></a>1.3.1.1 创建搜索配置文件</h3><p>主要是对搜索框样式的配置，文件保存在<code>res/xml/searchable.xml</code>:<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="pi">&lt;?xml version="1.0" encoding="utf-8"?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">searchable</span> <span class="attribute">xmlns:android</span>=<span class="value">"http://schemas.android.com/apk/res/android"</span></span><br><span class="line">    <span class="attribute">android:label</span>=<span class="value">"@string/app_label"</span></span><br><span class="line">    <span class="attribute">android:hint</span>=<span class="value">"@string/search_hint"</span> &gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">searchable</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<h3 id="1-3-1-2__u521B_u5EFAActivity_u5E76_u6CE8_u518C"><a href="#1-3-1-2__u521B_u5EFAActivity_u5E76_u6CE8_u518C" class="headerlink" title="1.3.1.2 创建Activity并注册"></a>1.3.1.2 创建Activity并注册</h3><p>注册Activity有两个要点，一个是接收Intent.ACTION_SEARCH，另一个是搜索框的配置文件地址:<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">application</span> <span class="attribute">...</span> &gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">activity</span> <span class="attribute">android:name</span>=<span class="value">".SearchableActivity"</span> &gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">intent-filter</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">action</span> <span class="attribute">android:name</span>=<span class="value">"android.intent.action.SEARCH"</span> /&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="title">intent-filter</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">meta-data</span> <span class="attribute">android:name</span>=<span class="value">"android.app.searchable"</span></span><br><span class="line">                   <span class="attribute">android:resource</span>=<span class="value">"@xml/searchable"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="title">activity</span>&gt;</span></span><br><span class="line">    ...</span><br><span class="line"><span class="tag">&lt;/<span class="title">application</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<h3 id="1-3-1-3__u6267_u884C_u641C_u7D22_u8FC7_u7A0B"><a href="#1-3-1-3__u6267_u884C_u641C_u7D22_u8FC7_u7A0B" class="headerlink" title="1.3.1.3 执行搜索过程"></a>1.3.1.3 执行搜索过程</h3><p>搜索的执行过程又分为3步:</p>
<ul>
<li>接收查询: 收到Intent数据获取到搜索内容执行搜索</li>
<li>搜索你的资料: 通过SQLite的FTS3方式搜索或进行在线搜索</li>
<li>呈现结果: 使用ListView等展示结果</li>
</ul>
<p>此处展示接收查询的示例代码:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span> </span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle savedInstanceState)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">super</span>.onCreate(savedInstanceState);</span><br><span class="line">    setContentView(R.layout.search);</span><br><span class="line"> </span><br><span class="line">    <span class="comment">// Get the intent, verify the action and get the query </span></span><br><span class="line">    Intent intent = getIntent();</span><br><span class="line">    <span class="keyword">if</span> (Intent.ACTION_SEARCH.equals(intent.getAction())) &#123;</span><br><span class="line">      String query = intent.getStringExtra(SearchManager.QUERY);</span><br><span class="line">      doMySearch(query);</span><br><span class="line">    &#125; </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h3 id="1-3-1-4__u8FDB_u884C_u5B9E_u65F6_u641C_u7D22"><a href="#1-3-1-4__u8FDB_u884C_u5B9E_u65F6_u641C_u7D22" class="headerlink" title="1.3.1.4 进行实时搜索"></a>1.3.1.4 进行实时搜索</h3><p>如果要进行实时搜索，需要在Activity中重写onSearchRequested()方法，返回true代表成功消耗此请求，示例代码如下:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span> </span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">onSearchRequested</span><span class="params">()</span> </span>&#123; </span><br><span class="line">     Bundle appData = <span class="keyword">new</span> Bundle();</span><br><span class="line">     appData.putBoolean(SearchableActivity.JARGON, <span class="keyword">true</span>);</span><br><span class="line">     startSearch(<span class="keyword">null</span>, <span class="keyword">false</span>, appData, <span class="keyword">false</span>);</span><br><span class="line">     <span class="keyword">return</span> <span class="keyword">true</span>; </span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure></p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">// startSearch()中</span><br><span class="line">Bundle appData = getIntent().getBundleExtra(SearchManager.APP_DATA);</span><br><span class="line">if (appData != null) &#123;</span><br><span class="line">    boolean jargon = appData.getBoolean(SearchableActivity.JARGON);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h1 id="2-__u653B_u5165MainActivity"><a href="#2-__u653B_u5165MainActivity" class="headerlink" title="2. 攻入MainActivity"></a>2. 攻入MainActivity</h1><h2 id="2-1_ButterKnife"><a href="#2-1_ButterKnife" class="headerlink" title="2.1 ButterKnife"></a>2.1 ButterKnife</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MainActivity</span> <span class="keyword">extends</span> <span class="title">BaseActivity</span> <span class="keyword">implements</span> <span class="title">MainView</span></span>&#123;</span><br><span class="line">    <span class="annotation">@Bind</span>(R.id.toolbar) Toolbar toolbar;</span><br><span class="line">    <span class="annotation">@Bind</span>(R.id.refresher) SwipeRefreshLayout refreshLayout;</span><br><span class="line">    ...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>打开MainActivity。映入眼帘的是熟悉的ButterKnife，此处回顾一下ButterKnife的使用。<br><img src="http://7xqdz8.com1.z0.glb.clouddn.com/160409ButterKnife.png" alt="ButterKnife"></p>
<h3 id="2-1-1__u4F7F_u7528_u65B9_u6CD5"><a href="#2-1-1__u4F7F_u7528_u65B9_u6CD5" class="headerlink" title="2.1.1 使用方法"></a>2.1.1 使用方法</h3><ol>
<li>导库<br>下载jar包导入或者直接在gradle中加上 <code>compile &#39;com.jakewharton:butterknife:7.0.1&#39;</code>即可</li>
<li><code>@Bind</code>和 <code>ButterKnife.bind(Activity act);</code><br>看如下一段代码就能明白如何使用:<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ExampleActivity</span> <span class="keyword">extends</span> <span class="title">Activity</span> </span>&#123;</span><br><span class="line">  <span class="annotation">@Bind</span>(R.id.user) EditText username;</span><br><span class="line">  <span class="annotation">@Bind</span>(R.id.pass) EditText password;</span><br><span class="line"></span><br><span class="line">  <span class="annotation">@BindString</span>(R.string.login_error)</span><br><span class="line">  String loginErrorMessage;</span><br><span class="line"></span><br><span class="line">  <span class="annotation">@OnClick</span>(R.id.submit) <span class="function"><span class="keyword">void</span> <span class="title">submit</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="comment">// TODO call server...</span></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="annotation">@Override</span> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle savedInstanceState)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">super</span>.onCreate(savedInstanceState);</span><br><span class="line">    setContentView(R.layout.simple_activity);</span><br><span class="line">    ButterKnife.bind(<span class="keyword">this</span>);</span><br><span class="line">    <span class="comment">// TODO Use fields...</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<p>更多使用方法详见官方介绍，<a href="https://github.com/JakeWharton/butterknife" target="_blank" rel="external">JakeWharton/butterknife</a></p>
<h2 id="2-2__u57FA_u7C7B_u548C_u63A5_u53E3"><a href="#2-2__u57FA_u7C7B_u548C_u63A5_u53E3" class="headerlink" title="2.2 基类和接口"></a>2.2 基类和接口</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MainActivity</span> <span class="keyword">extends</span> <span class="title">BaseActivity</span> <span class="keyword">implements</span> <span class="title">MainView</span></span>&#123;</span><br><span class="line">    ...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>从这里，可以进入基类BaseActivity和接口MainView看看。</p>
<h3 id="2-2-1__u91CD_u5199Activity_u751F_u547D_u5468_u671F_u7684BaseActivity"><a href="#2-2-1__u91CD_u5199Activity_u751F_u547D_u5468_u671F_u7684BaseActivity" class="headerlink" title="2.2.1 重写Activity生命周期的BaseActivity"></a>2.2.1 重写Activity生命周期的BaseActivity</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle savedInstanceState)</span> </span>&#123;</span><br><span class="line">    parseIntent(getIntent());</span><br><span class="line">    showActivityInAnim();</span><br><span class="line">    initTheme();</span><br><span class="line">    <span class="keyword">super</span>.onCreate(savedInstanceState);</span><br><span class="line">    initWindow();</span><br><span class="line">    initializeDependencyInjector();</span><br><span class="line">    setContentView(getLayoutView());</span><br><span class="line">    ButterKnife.bind(<span class="keyword">this</span>);</span><br><span class="line">    initToolbar();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>通过这样重写生命周期的方式可以使代码更加统一，便于后期管理和维护。<br>下面就简单分析几个方法: </p>
<h4 id="2-2-1-1__u5904_u7406_u6570_u636E"><a href="#2-2-1-1__u5904_u7406_u6570_u636E" class="headerlink" title="2.2.1.1 处理数据"></a>2.2.1.1 处理数据</h4><p>通过 <code>parseIntent(getIntent());</code>处理传递到Activity的数据，可以进行一些初始化操作。</p>
<h4 id="2-2-1-2__u8FC7_u6E21_u52A8_u753B"><a href="#2-2-1-2__u8FC7_u6E21_u52A8_u753B" class="headerlink" title="2.2.1.2 过渡动画"></a>2.2.1.2 过渡动画</h4><p>回顾一下Activity过渡动画的使用方法:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">overridePendingTransition(R.anim.activity_down_up_anim, R.anim.activity_exit_anim);</span><br></pre></td></tr></table></figure></p>
<p>xml中定义的动画:<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">set</span> <span class="attribute">xmlns:android</span>=<span class="value">"http://schemas.android.com/apk/res/android"</span></span><br><span class="line">    <span class="attribute">android:interpolator</span>=<span class="value">"@android:anim/decelerate_interpolator"</span> &gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">translate</span></span><br><span class="line">        <span class="attribute">android:duration</span>=<span class="value">"@android:integer/config_shortAnimTime"</span></span><br><span class="line">        <span class="attribute">android:fromYDelta</span>=<span class="value">"10%p"</span></span><br><span class="line">        <span class="attribute">android:toYDelta</span>=<span class="value">"0"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">set</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<blockquote>
<p>两点注意:</p>
<ul>
<li>此处笔者测试了下，即便 <code>android:fromYDelta=&quot;100%p&quot;</code>中为100%p，也不能省略为p。</li>
<li>窗体过渡动画不一定要在setContentView之前执行，可以在onCreate()中任意位置执行</li>
</ul>
</blockquote>
<h4 id="2-2-1-3__u4E3B_u9898_u5207_u6362"><a href="#2-2-1-3__u4E3B_u9898_u5207_u6362" class="headerlink" title="2.2.1.3 主题切换"></a>2.2.1.3 主题切换</h4><p>主题切换是通过Activity中继承自ContextThemeWrapper的setTheme(int resid)方法实现的。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">int</span> style = R.style.RedTheme;</span><br><span class="line">activity.setTheme(style);</span><br></pre></td></tr></table></figure></p>
<p>styles中定义了多种样式:<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">style</span> <span class="attribute">name</span>=<span class="value">"RedTheme"</span> <span class="attribute">parent</span>=<span class="value">"AppBaseTheme.Dark"</span>&gt;</span><span class="css"></span><br><span class="line">    &lt;<span class="tag">item</span> <span class="tag">name</span>="<span class="tag">colorPrimary</span>"&gt;<span class="at_rule">@<span class="keyword">color/red&lt;/item&gt;</span></span><br><span class="line">    &lt;item name=<span class="string">"colorPrimaryDark"</span>&gt;@color/dark_red&lt;/item&gt;</span><br><span class="line">    &lt;item name=<span class="string">"colorAccent"</span>&gt;@color/accent_red&lt;/item&gt;</span><br><span class="line"></span></span><span class="tag">&lt;/<span class="title">style</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<h4 id="2-2-1-4__u9488_u5BF9KitKat_u7684_u72B6_u6001_u680F_u201D_u6C89_u6D78_u6A21_u5F0F_u201D"><a href="#2-2-1-4__u9488_u5BF9KitKat_u7684_u72B6_u6001_u680F_u201D_u6C89_u6D78_u6A21_u5F0F_u201D" class="headerlink" title="2.2.1.4 针对KitKat的状态栏”沉浸模式”"></a>2.2.1.4 针对KitKat的状态栏”沉浸模式”</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@TargetApi</span>(<span class="number">19</span>)</span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">initWindow</span><span class="params">()</span></span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT)&#123;</span><br><span class="line">        getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);</span><br><span class="line">        getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);</span><br><span class="line">        SystemBarTintManager tintManager = <span class="keyword">new</span> SystemBarTintManager(<span class="keyword">this</span>);</span><br><span class="line">        tintManager.setStatusBarTintColor(getStatusBarColor());</span><br><span class="line">        tintManager.setStatusBarTintEnabled(<span class="keyword">true</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>针对安卓4.4系统，通过使用 <code>SystemBarTintManager</code> 开源库实现了状态栏变色功能。</p>
<h4 id="2-2-1-5__u89C6_u56FE_u521D_u59CB_u5316"><a href="#2-2-1-5__u89C6_u56FE_u521D_u59CB_u5316" class="headerlink" title="2.2.1.5 视图初始化"></a>2.2.1.5 视图初始化</h4><p>通过 <code>setContentView(getLayoutView());</code> 也巧妙将布局设置转移给子类实现 <code>getLayoutView()</code> 抽象方法。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">int</span> <span class="title">getLayoutView</span><span class="params">()</span> </span>&#123; <span class="keyword">return</span> R.layout.activity_main; &#125;</span><br></pre></td></tr></table></figure></p>
<p>通过这里我们也就又发现了新大陆，哦不，新道路，通往Activity布局文件的道路。</p>
<h4 id="2-2-1-6_Toolbar_u521D_u59CB_u5316"><a href="#2-2-1-6_Toolbar_u521D_u59CB_u5316" class="headerlink" title="2.2.1.6 Toolbar初始化"></a>2.2.1.6 Toolbar初始化</h4><p>由于各Activity中toolbar都一样，所以这里就将其抽取出来了，布局文件中使用 <code>&lt;include&gt;</code> 标签抽取，Activity中抽取出来一个ToolbarUtils类。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ToolbarUtils</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">initToolbar</span><span class="params">(Toolbar toolbar, AppCompatActivity activity)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (toolbar == <span class="keyword">null</span> || activity == <span class="keyword">null</span>)</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        <span class="keyword">if</span> (activity <span class="keyword">instanceof</span> BaseActivity)&#123;</span><br><span class="line">            toolbar.setBackgroundColor(((BaseActivity) activity).getColorPrimary());</span><br><span class="line">        &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">            toolbar.setBackgroundColor(activity.getResources().getColor(R.color.toolbar_bg_color));</span><br><span class="line">        &#125;</span><br><span class="line">        toolbar.setTitle(R.string.app_name);</span><br><span class="line">        toolbar.setTitleTextColor(activity.getResources().getColor(R.color.toolbar_title_color));</span><br><span class="line">        toolbar.collapseActionView();</span><br><span class="line">        activity.setSupportActionBar(toolbar);</span><br><span class="line">        <span class="keyword">if</span> (activity.getSupportActionBar() != <span class="keyword">null</span>)&#123;</span><br><span class="line">            activity.getSupportActionBar().setHomeAsUpIndicator(R.drawable.abc_ic_ab_back_mtrl_am_alpha);</span><br><span class="line">            activity.getSupportActionBar().setDisplayHomeAsUpEnabled(<span class="keyword">true</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h4 id="2-2-1-7__u91CD_u542FActivity"><a href="#2-2-1-7__u91CD_u542FActivity" class="headerlink" title="2.2.1.7 重启Activity"></a>2.2.1.7 重启Activity</h4><p>BaseActivity中还包含一个reload()方法，用于没有动画的重启自身Activity，以便应用新的主题。关于不重启应用新样式主题，读者感兴趣可以去了解知乎的不重启Activity切换主题解决方案。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">reload</span><span class="params">(<span class="keyword">boolean</span> anim)</span> </span>&#123;</span><br><span class="line">    Intent intent = getIntent();</span><br><span class="line">    <span class="keyword">if</span> (!anim) &#123;</span><br><span class="line">        overridePendingTransition(<span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line">        intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);</span><br><span class="line">        intent.putExtra(BaseActivity.IS_START_ANIM, <span class="keyword">false</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    finish();</span><br><span class="line">    <span class="keyword">if</span> (!anim) &#123;</span><br><span class="line">        overridePendingTransition(<span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    startActivity(intent);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>至此，BaseActivity分析得差不多了，接下来回到MainActivity。</p>
<h3 id="2-2-2_MainView_u63A5_u53E3"><a href="#2-2-2_MainView_u63A5_u53E3" class="headerlink" title="2.2.2 MainView接口"></a>2.2.2 MainView接口</h3><p>回到MainActivity再看看MainView接口，此接口主要是对BaseActivity里的共有方法进行抽象。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">MainView</span> <span class="keyword">extends</span> <span class="title">View</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">initToolbar</span><span class="params">()</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">initDrawerView</span><span class="params">(List&lt;String&gt; list)</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">setToolbarTitle</span><span class="params">(String title)</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">showProgressWheel</span><span class="params">(<span class="keyword">boolean</span> visible)</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">switchNoteTypePage</span><span class="params">(List&lt;SNote&gt; notes)</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">addNote</span><span class="params">(SNote note)</span></span>;</span><br><span class="line">    ...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<blockquote>
<p>注意View接口是在本项目中的接口，而非android.view.View</p>
</blockquote>
<h2 id="2-3_MainPresenter_u6865_u6881"><a href="#2-3_MainPresenter_u6865_u6881" class="headerlink" title="2.3 MainPresenter桥梁"></a>2.3 MainPresenter桥梁</h2><p>大致浏览MainActivity，可以看到到处都是MainPresenter的影子，这便是MVP的架构思想，在MainActivity中将逻辑操作转交给MainPresenter去执行。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 初始化依赖注入</span></span><br><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">initializeDependencyInjector</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    App app = (App) getApplication();</span><br><span class="line">    mActivityComponent = DaggerActivityComponent.builder()</span><br><span class="line">            .activityModule(<span class="keyword">new</span> ActivityModule(<span class="keyword">this</span>))</span><br><span class="line">            .appComponent(app.getAppComponent())</span><br><span class="line">            .build();</span><br><span class="line">    mActivityComponent.inject(<span class="keyword">this</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>那么显然在MainActivity分析完成后的下一个目标就是MainPresenter了，现在先不急，继续分析MainActivity。</p>
<h2 id="2-4_onCreate_28_29_u7684_u91CD_u5199"><a href="#2-4_onCreate_28_29_u7684_u91CD_u5199" class="headerlink" title="2.4 onCreate()的重写"></a>2.4 onCreate()的重写</h2><p>在MainActivity中，并没有使用BaseActivity重写的生命周期，而是再次重写onCreate()方法，以独具一格。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle savedInstanceState)</span> </span>&#123;</span><br><span class="line">    launchWithNoAnim();</span><br><span class="line">    <span class="keyword">super</span>.onCreate(savedInstanceState);</span><br><span class="line">    initializePresenter();</span><br><span class="line">    mainPresenter.onCreate(savedInstanceState);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h2 id="2-5__u4E3B_u5E03_u5C40_u6587_u4EF6_u5206_u6790"><a href="#2-5__u4E3B_u5E03_u5C40_u6587_u4EF6_u5206_u6790" class="headerlink" title="2.5 主布局文件分析"></a>2.5 主布局文件分析</h2><p>通过 <code>getLayoutView()</code> 可以找到主Activity对应的布局文件。主布局由ToolBar和DrawerLayout组成，DrawerLayout中包含RecyclerView正文界面和ListView侧滑界面，为了更好兼容低版本安卓系统，使低版本也能够拥有5.0以上版本的特效，大量使用了第三方库和自定义控件。</p>
<h3 id="2-5-1__u5934_u58F0_u660E"><a href="#2-5-1__u5934_u58F0_u660E" class="headerlink" title="2.5.1 头声明"></a>2.5.1 头声明</h3><p>此处注意xmlns多个是可以省略为一个的，并不会影响程序的执行，但为了代码的可读性，还是应该写成多个。<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">xmlns:fab="http://schemas.android.com/apk/res-auto"</span><br><span class="line">xmlns:app="http://schemas.android.com/apk/res-auto"</span><br><span class="line">xmlns:wheel="http://schemas.android.com/apk/res-auto"</span><br></pre></td></tr></table></figure></p>
<h3 id="2-5-2_FixedRecyclerView"><a href="#2-5-2_FixedRecyclerView" class="headerlink" title="2.5.2 FixedRecyclerView"></a>2.5.2 FixedRecyclerView</h3><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">com.lguipeng.notes.view.FixedRecyclerView</span></span><br><span class="line">    <span class="attribute">android:id</span>=<span class="value">"@+id/recyclerView"</span></span><br><span class="line">    <span class="attribute">android:padding</span>=<span class="value">"4dp"</span></span><br><span class="line">    <span class="attribute">android:layout_width</span>=<span class="value">"match_parent"</span></span><br><span class="line">    <span class="attribute">android:layout_height</span>=<span class="value">"match_parent"</span>/&gt;</span></span><br></pre></td></tr></table></figure>
<p>这个是作者的一个修正后的RecyclerView控件。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">FixedRecyclerView</span> <span class="keyword">extends</span> <span class="title">RecyclerView</span> </span>&#123;</span><br><span class="line">    </span><br><span class="line">    ...</span><br><span class="line">    </span><br><span class="line">    <span class="annotation">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">canScrollVertically</span><span class="params">(<span class="keyword">int</span> direction)</span> </span>&#123;</span><br><span class="line">        <span class="comment">// check if scrolling up</span></span><br><span class="line">        <span class="keyword">if</span> (direction &lt; <span class="number">1</span>) &#123;</span><br><span class="line">            <span class="keyword">boolean</span> original = <span class="keyword">super</span>.canScrollVertically(direction);</span><br><span class="line">            <span class="keyword">return</span> !original &amp;&amp; getChildAt(<span class="number">0</span>) != <span class="keyword">null</span> &amp;&amp; getChildAt(<span class="number">0</span>).getTop() &lt; <span class="number">0</span> || original;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">super</span>.canScrollVertically(direction);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>这段代码暂时有些难以理解，此处就不详细分析了。此处读者可以去回顾RecyclerView的用法。在MainActivity中，对RecyclerView进行了初始化:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">initRecyclerView</span><span class="params">(List&lt;SNote&gt; notes)</span></span>&#123;</span><br><span class="line">    recyclerAdapter = <span class="keyword">new</span> NotesAdapter(notes, <span class="keyword">this</span>);</span><br><span class="line">    recyclerView.setHasFixedSize(<span class="keyword">true</span>);</span><br><span class="line">    recyclerAdapter.setOnInViewClickListener(R.id.notes_item_root,</span><br><span class="line">            <span class="keyword">new</span> BaseRecyclerViewAdapter.onInternalClickListenerImpl&lt;SNote&gt;() &#123;</span><br><span class="line">                <span class="annotation">@Override</span></span><br><span class="line">                <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">OnClickListener</span><span class="params">(View parentV, View v, Integer position, SNote values)</span> </span>&#123;</span><br><span class="line">                    <span class="keyword">super</span>.OnClickListener(parentV, v, position, values);</span><br><span class="line">                    mainPresenter.onRecyclerViewItemClick(position, values);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;);</span><br><span class="line">    recyclerAdapter.setOnInViewClickListener(R.id.note_more,</span><br><span class="line">            <span class="keyword">new</span> BaseRecyclerViewAdapter.onInternalClickListenerImpl&lt;SNote&gt;() &#123;</span><br><span class="line">                <span class="annotation">@Override</span></span><br><span class="line">                <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">OnClickListener</span><span class="params">(View parentV, View v, Integer position, SNote values)</span> </span>&#123;</span><br><span class="line">                    <span class="keyword">super</span>.OnClickListener(parentV, v, position, values);</span><br><span class="line">                    mainPresenter.showPopMenu(v, position, values);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;);</span><br><span class="line">    recyclerAdapter.setFirstOnly(<span class="keyword">false</span>);</span><br><span class="line">    recyclerAdapter.setDuration(<span class="number">300</span>);</span><br><span class="line">    recyclerView.setAdapter(recyclerAdapter);</span><br><span class="line">    refreshLayout.setColorSchemeColors(getColorPrimary());</span><br><span class="line">    refreshLayout.setOnRefreshListener(mainPresenter);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>当中，设置了recyclerView的 <code>NotesAdapter</code> 适配器，设置了SwipeRefreshLayout的主题颜色和刷新监听器，当然也传递给MainPresenter进行处理。</p>
<h3 id="2-5-3_ProgressWheel"><a href="#2-5-3_ProgressWheel" class="headerlink" title="2.5.3 ProgressWheel"></a>2.5.3 ProgressWheel</h3><p>ProgressWheel为 <code>materialish-progress</code> 库中的一个进度环控件，在安卓低版本中实现MaterialDesign中自带效果，用法代码如下:<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">com.pnikosis.materialishprogress.ProgressWheel</span></span><br><span class="line">    <span class="attribute">android:id</span>=<span class="value">"@+id/progress_wheel"</span></span><br><span class="line">    <span class="attribute">android:layout_width</span>=<span class="value">"75dp"</span></span><br><span class="line">    <span class="attribute">android:layout_height</span>=<span class="value">"75dp"</span></span><br><span class="line">    <span class="attribute">android:visibility</span>=<span class="value">"visible"</span></span><br><span class="line">    <span class="attribute">android:layout_gravity</span>=<span class="value">"center"</span></span><br><span class="line">    <span class="attribute">wheel:matProg_spinSpeed</span>=<span class="value">"1.2"</span></span><br><span class="line">    <span class="attribute">wheel:matProg_barColor</span>=<span class="value">"?attr/colorPrimary"</span></span><br><span class="line">    <span class="attribute">wheel:matProg_progressIndeterminate</span>=<span class="value">"true"</span> /&gt;</span></span><br></pre></td></tr></table></figure></p>
<h3 id="2-5-4_Toolbar_u9634_u5F71"><a href="#2-5-4_Toolbar_u9634_u5F71" class="headerlink" title="2.5.4 Toolbar阴影"></a>2.5.4 Toolbar阴影</h3><p>如何解决Toolbar在低版本安卓上效果不好，比如没有阴影效果，作者很机智地include了一个阴影效果布局:<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">View</span></span><br><span class="line">    <span class="attribute">xmlns:android</span>=<span class="value">"http://schemas.android.com/apk/res/android"</span></span><br><span class="line">    <span class="attribute">android:layout_width</span>=<span class="value">"match_parent"</span></span><br><span class="line">    <span class="attribute">android:layout_height</span>=<span class="value">"6dp"</span></span><br><span class="line">    <span class="attribute">android:background</span>=<span class="value">"@drawable/toolbar_shadow"</span> /&gt;</span></span><br></pre></td></tr></table></figure></p>
<p>drawable/toolbar_shadow:<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">shape</span> <span class="attribute">xmlns:android</span>=<span class="value">"http://schemas.android.com/apk/res/android"</span> <span class="attribute">android:shape</span>=<span class="value">"rectangle"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">gradient</span></span><br><span class="line">        <span class="attribute">android:startColor</span>=<span class="value">"@android:color/transparent"</span></span><br><span class="line">        <span class="attribute">android:endColor</span>=<span class="value">"@color/light_grey"</span></span><br><span class="line">        <span class="attribute">android:angle</span>=<span class="value">"90"</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">shape</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<h3 id="2-5-5_BetterFab"><a href="#2-5-5_BetterFab" class="headerlink" title="2.5.5 BetterFab"></a>2.5.5 BetterFab</h3><p>BetterFab也是作者重写的一个基于FloatingActionButton的自定义控件，主要增加了强制隐藏方法，该功能体现在 <code>回收站</code> 功能中FloatingActionButton被隐藏掉了，也得以猜测到此应用中抽屉切换并非切换Fragment而是通过隐藏和显示模块实现的。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BetterFab</span> <span class="keyword">extends</span> <span class="title">FloatingActionButton</span></span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">boolean</span> forceHide = <span class="keyword">false</span>;</span><br><span class="line">    ...</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setForceHide</span><span class="params">(<span class="keyword">boolean</span> forceHide)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.forceHide = forceHide;</span><br><span class="line">        <span class="keyword">if</span> (!forceHide) &#123;</span><br><span class="line">            setVisibility(VISIBLE);</span><br><span class="line">        &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">            setVisibility(GONE);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//if hide，disable animation</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">canAnimation</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> !isForceHide();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h3 id="2-5-6__u62BD_u5C49_u4E2D_u7684ListView"><a href="#2-5-6__u62BD_u5C49_u4E2D_u7684ListView" class="headerlink" title="2.5.6 抽屉中的ListView"></a>2.5.6 抽屉中的ListView</h3><p>抽屉中的ListView包含了几个不常用的属性，值得一看。<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">ListView</span> <span class="attribute">android:id</span>=<span class="value">"@+id/left_drawer_listview"</span></span><br><span class="line">    <span class="attribute">android:layout_width</span>=<span class="value">"@dimen/drawer_width"</span></span><br><span class="line">    <span class="attribute">android:layout_height</span>=<span class="value">"0dp"</span></span><br><span class="line">    <span class="attribute">android:layout_weight</span>=<span class="value">"1.0"</span></span><br><span class="line">    <span class="attribute">android:choiceMode</span>=<span class="value">"singleChoice"</span></span><br><span class="line">    <span class="attribute">android:divider</span>=<span class="value">"@android:color/transparent"</span></span><br><span class="line">    <span class="attribute">android:dividerHeight</span>=<span class="value">"0dp"</span></span><br><span class="line">    <span class="attribute">android:background</span>=<span class="value">"?attr/colorPrimary"</span>/&gt;</span></span><br></pre></td></tr></table></figure></p>
<ul>
<li>choiceMode: 选择模式: 多选和单选，默认不设定，此处单选便于用户知道自己所在的选项卡，如图所示:</li>
</ul>
<p><img src="http://7xqdz8.com1.z0.glb.clouddn.com/160410none.png" alt="None模式"><img src="http://7xqdz8.com1.z0.glb.clouddn.com/160410single.png" alt="单选模式"></p>
<ul>
<li>divider: 分隔线</li>
<li>dividerHeight: 分隔线高度</li>
</ul>
<p>分析完主布局，继续回到MainActivity。</p>
<h2 id="2-6_NotesAdapter"><a href="#2-6_NotesAdapter" class="headerlink" title="2.6 NotesAdapter"></a>2.6 NotesAdapter</h2><p>首先回到之前提到了RecyclerView，其中的NotesAdapter是一个比较重要的东西，关乎着笔记列表的展示和操作。</p>
<h3 id="2-6-1__u627F_u63A5_u5173_u7CFB"><a href="#2-6-1__u627F_u63A5_u5173_u7CFB" class="headerlink" title="2.6.1 承接关系"></a>2.6.1 承接关系</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">NotesAdapter</span> <span class="keyword">extends</span> <span class="title">BaseRecyclerViewAdapter</span>&lt;<span class="title">SNote</span>&gt; <span class="keyword">implements</span> <span class="title">Filterable</span> </span>&#123;</span><br><span class="line">    ...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>继承自BaseRecyclerViewAdapter<e>，而BaseRecyclerViewAdapter<e>才继承自真正应该继承的RecyclerView.Adapter<recyclerview.viewholder>，同时实现了Filterable接口，便于笔记列表的过滤操作，笔者猜测是用于搜索功能的过滤操作，那接下来就先分析其父类BaseRecyclerViewAdapter。</recyclerview.viewholder></e></e></p>
<h4 id="2-6-1-1_BaseRecyclerViewAdapter"><a href="#2-6-1-1_BaseRecyclerViewAdapter" class="headerlink" title="2.6.1.1 BaseRecyclerViewAdapter"></a>2.6.1.1 BaseRecyclerViewAdapter<e></e></h4><h5 id="2-6-1-1-1__u589E_u5220_u6539_u65B9_u6CD5"><a href="#2-6-1-1-1__u589E_u5220_u6539_u65B9_u6CD5" class="headerlink" title="2.6.1.1.1 增删改方法"></a>2.6.1.1.1 增删改方法</h5><p>在BaseRecyclerViewAdapter中，首先是增加了对传入List的增删改方法，此处只贴上增加的方法:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">add</span><span class="params">(E e)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">this</span>.list.add(<span class="number">0</span>, e);</span><br><span class="line">    notifyItemInserted(<span class="number">0</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>此处notifyItemInserted(int position)方法是用于通知RecyclerView有新的数据增加，对于不使用notifyDataSetChanged()方法，笔者猜测是为了防止刷新数据时列表跳回到表首。</p>
<h5 id="2-6-1-1-2__u5185_u90E8_u70B9_u51FB_u4E8B_u4EF6"><a href="#2-6-1-1-2__u5185_u90E8_u70B9_u51FB_u4E8B_u4EF6" class="headerlink" title="2.6.1.1.2 内部点击事件"></a>2.6.1.1.2 内部点击事件</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">addInternalClickListener</span><span class="params">(<span class="keyword">final</span> View itemV, <span class="keyword">final</span> Integer position, <span class="keyword">final</span> E valuesMap)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (canClickItem != <span class="keyword">null</span>) &#123;</span><br><span class="line">        <span class="keyword">for</span> (Integer key : canClickItem.keySet()) &#123;</span><br><span class="line">            View inView = itemV.findViewById(key);</span><br><span class="line">            <span class="keyword">final</span> onInternalClickListener&lt;E&gt; listener = canClickItem.get(key);</span><br><span class="line">            <span class="keyword">if</span> (inView != <span class="keyword">null</span> &amp;&amp; listener != <span class="keyword">null</span>) &#123;</span><br><span class="line">                inView.setOnClickListener((view) -&gt;</span><br><span class="line">                        listener.OnClickListener(itemV, view, position,</span><br><span class="line">                                valuesMap)</span><br><span class="line">                );</span><br><span class="line">                inView.setOnLongClickListener((view) -&gt; &#123;</span><br><span class="line">                    listener.OnLongClickListener(itemV, view, position,</span><br><span class="line">                            valuesMap);</span><br><span class="line">                    <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">                &#125;);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>这段代码逻辑比较复杂，主要是对内部的点击事件进行回调，暂时先不作详细分析。</p>
<h5 id="2-6-1-1-3__u52A8_u753B_u6548_u679C"><a href="#2-6-1-1-3__u52A8_u753B_u6548_u679C" class="headerlink" title="2.6.1.1.3 动画效果"></a>2.6.1.1.3 动画效果</h5><p>首先animate方法用于执行getAnimators()中获得的所有动画效果:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">animate</span><span class="params">(RecyclerView.ViewHolder holder, <span class="keyword">int</span> position)</span></span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (!isFirstOnly || position &gt; mLastPosition) &#123;</span><br><span class="line">        <span class="keyword">for</span> (Animator anim : getAnimators(holder.itemView)) &#123;</span><br><span class="line">            anim.setDuration(mDuration).start();</span><br><span class="line">            anim.setInterpolator(mInterpolator);</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line">        mLastPosition = position;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        ViewHelper.clear(holder.itemView);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>getAnimators()方法在子类NotesAdapter进行实现:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="keyword">protected</span> Animator[] getAnimators(View view) &#123;</span><br><span class="line">    <span class="keyword">if</span> (view.getMeasuredHeight() &lt;=<span class="number">0</span>)&#123;</span><br><span class="line">        ObjectAnimator scaleX = ObjectAnimator.ofFloat(view, <span class="string">"scaleX"</span>, <span class="number">1.05f</span>, <span class="number">1.0f</span>);</span><br><span class="line">        ObjectAnimator scaleY = ObjectAnimator.ofFloat(view, <span class="string">"scaleY"</span>, <span class="number">1.05f</span>, <span class="number">1.0f</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> ObjectAnimator[]&#123;scaleX, scaleY&#125;;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> Animator[]&#123;</span><br><span class="line">            ObjectAnimator.ofFloat(view, <span class="string">"scaleX"</span>, <span class="number">1.05f</span>, <span class="number">1.0f</span>),</span><br><span class="line">            ObjectAnimator.ofFloat(view, <span class="string">"scaleY"</span>, <span class="number">1.05f</span>, <span class="number">1.0f</span>),</span><br><span class="line">    &#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>此处用到了属性动画相关知识。</p>
<h3 id="2-6-2_onCreateViewHolder"><a href="#2-6-2_onCreateViewHolder" class="headerlink" title="2.6.2 onCreateViewHolder"></a>2.6.2 onCreateViewHolder</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="keyword">public</span> RecyclerView.<span class="function">ViewHolder <span class="title">onCreateViewHolder</span><span class="params">(ViewGroup parent, <span class="keyword">int</span> viewType)</span> </span>&#123;</span><br><span class="line">    mContext = parent.getContext();</span><br><span class="line">    <span class="keyword">final</span> View view = LayoutInflater.from(mContext).inflate(R.layout.notes_item_layout, parent, <span class="keyword">false</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> NotesItemViewHolder(view);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>在创建单个Item视图的ViewHolder时，先使用LayoutInflater填充出一个view，再通过NotesItemViewHolder包装获得ViewHolder。</p>
<h4 id="2-6-2-1_NotesItemViewHolder"><a href="#2-6-2-1_NotesItemViewHolder" class="headerlink" title="2.6.2.1 NotesItemViewHolder"></a>2.6.2.1 NotesItemViewHolder</h4><p>NotesItemViewHolder继承自RecyclerView.ViewHolder，是一个为了提高性能的ViewHolder。<br>首先看构造函数:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">final</span> TextView mNoteLabelTextView;</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">final</span> TextView mNoteContentTextView;</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">final</span> TextView mNoteTimeTextView;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">NotesItemViewHolder</span><span class="params">(View parent)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">super</span>(parent);</span><br><span class="line">    mNoteLabelTextView = (TextView) parent.findViewById(R.id.note_label_text);</span><br><span class="line">    mNoteContentTextView = (TextView) parent.findViewById(R.id.note_content_text);</span><br><span class="line">    mNoteTimeTextView = (TextView) parent.findViewById(R.id.note_last_edit_text);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>这里并没有使用ButterKnife，也许是因为ButterKnife的使用有需要传入Activity参数的限制，或是因为成员变量为final类型，需要即时初始化。<br>类中还包含设置TextView的方法，用于设置每个Item View的文字。</p>
<h3 id="2-6-3__u7ED1_u5B9AViewHolder"><a href="#2-6-3__u7ED1_u5B9AViewHolder" class="headerlink" title="2.6.3 绑定ViewHolder"></a>2.6.3 绑定ViewHolder</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onBindViewHolder</span><span class="params">(RecyclerView.ViewHolder viewHolder, <span class="keyword">int</span> position)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">super</span>.onBindViewHolder(viewHolder, position);</span><br><span class="line">    NotesItemViewHolder holder = (NotesItemViewHolder) viewHolder;</span><br><span class="line">    SNote note = list.get(position);</span><br><span class="line">    <span class="keyword">if</span> (note == <span class="keyword">null</span>)</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    String label = <span class="string">""</span>;</span><br><span class="line">    <span class="keyword">if</span> (mContext != <span class="keyword">null</span>) &#123;</span><br><span class="line">        <span class="keyword">boolean</span> b  = TextUtils.equals(mContext.getString(R.string.default_label), note.getLabel());</span><br><span class="line">        label = b? <span class="string">""</span>: note.getLabel();</span><br><span class="line">    &#125;</span><br><span class="line">    holder.setLabelText(label);</span><br><span class="line">    holder.setContentText(note.getContent());</span><br><span class="line">    holder.setTimeText(TimeUtils.getConciseTime(note.getLastOprTime(), mContext));</span><br><span class="line">    animate(viewHolder, position);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>此方法主要对ViewHolder中的控件进行赋值，在加载每个子项时调用此方法。</p>
<h3 id="2-6-4__u8FC7_u6EE4_u64CD_u4F5C"><a href="#2-6-4__u8FC7_u6EE4_u64CD_u4F5C" class="headerlink" title="2.6.4 过滤操作"></a>2.6.4 过滤操作</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">NoteFilter</span> <span class="keyword">extends</span> <span class="title">Filter</span></span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> NotesAdapter adapter;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> List&lt;SNote&gt; originalList;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> List&lt;SNote&gt; filteredList;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="title">NoteFilter</span><span class="params">(NotesAdapter adapter, List&lt;SNote&gt; originalList)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">super</span>();</span><br><span class="line">        <span class="keyword">this</span>.adapter = adapter;</span><br><span class="line">        <span class="keyword">this</span>.originalList = <span class="keyword">new</span> LinkedList&lt;&gt;(originalList);</span><br><span class="line">        <span class="keyword">this</span>.filteredList = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> FilterResults <span class="title">performFiltering</span><span class="params">(CharSequence constraint)</span> </span>&#123;</span><br><span class="line">        filteredList.clear();</span><br><span class="line">        <span class="keyword">final</span> FilterResults results = <span class="keyword">new</span> FilterResults();</span><br><span class="line">        <span class="keyword">if</span> (constraint.length() == <span class="number">0</span>) &#123;</span><br><span class="line">            filteredList.addAll(originalList);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">for</span> ( SNote note : originalList) &#123;</span><br><span class="line">                <span class="keyword">if</span> (note.getContent().contains(constraint) || note.getLabel().contains(constraint)) &#123;</span><br><span class="line">                    filteredList.add(note);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        results.values = filteredList;</span><br><span class="line">        results.count = filteredList.size();</span><br><span class="line">        <span class="keyword">return</span> results;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">publishResults</span><span class="params">(CharSequence constraint, FilterResults results)</span> </span>&#123;</span><br><span class="line">        adapter.list.clear();</span><br><span class="line">        adapter.list.addAll((ArrayList&lt;SNote&gt;) results.values);</span><br><span class="line">        adapter.notifyDataSetChanged();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>此类主要由搜索功能调用，构造函数对originalList进行赋值，performFiltering(…)方法进行过滤操作，过滤后列表存入filteredList，并且返回FilterResults以便后用，publishResults(…)方法进行展示filteredList的内容。</p>
<h2 id="2-7_DrawerView_u7684_u521D_u59CB_u5316"><a href="#2-7_DrawerView_u7684_u521D_u59CB_u5316" class="headerlink" title="2.7 DrawerView的初始化"></a>2.7 DrawerView的初始化</h2><p>DrawerView视图比较简单，只有一个ListView，不过其中包含很多细节值得学习，而且作者为了后期的可拓展性定义了抽象类和接口。</p>
<h3 id="2-7-1_DrawerListAdapter"><a href="#2-7-1_DrawerListAdapter" class="headerlink" title="2.7.1 DrawerListAdapter"></a>2.7.1 DrawerListAdapter</h3><p>首先是DrawerListAdapter，继承自SimpleListAdapter，而SimpleListAdapter又继承自BaseListAdapter<e>，然后才是继承自API的BaseAdapter，继承结构如图:<br><img src="http://7xqdz8.com1.z0.glb.clouddn.com/160411class.png" alt="DrawerListAdapter类继承结构图"></e></p>
<blockquote>
<p>Android Studio中按快捷键F4查看类继承结构图</p>
</blockquote>
<h4 id="2-7-1-1_BaseListAdapter"><a href="#2-7-1-1_BaseListAdapter" class="headerlink" title="2.7.1.1 BaseListAdapter"></a>2.7.1.1 BaseListAdapter<e></e></h4><p>与BaseRecyclerViewAdapter<e>类似，同样包含需要传入参数进行初始化操作的列表，以及增删改方法，以及回调的点击事件接口。</e></p>
<h4 id="2-7-1-2_SimpleListAdapter"><a href="#2-7-1-2_SimpleListAdapter" class="headerlink" title="2.7.1.2 SimpleListAdapter"></a>2.7.1.2 SimpleListAdapter</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> View <span class="title">bindView</span><span class="params">(<span class="keyword">int</span> position, View convertView, ViewGroup parent)</span> </span>&#123;</span><br><span class="line">    Holder holder;</span><br><span class="line">    <span class="keyword">if</span> (convertView == <span class="keyword">null</span>)&#123;</span><br><span class="line">        convertView = LayoutInflater.from(mContext).inflate(getLayout(), <span class="keyword">null</span>);</span><br><span class="line">        holder = <span class="keyword">new</span> Holder();</span><br><span class="line">        holder.textView = (TextView)convertView.findViewById(R.id.textView);</span><br><span class="line">        convertView.setTag(holder);</span><br><span class="line">    &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">        holder = (Holder)convertView.getTag();</span><br><span class="line">    &#125;</span><br><span class="line">    holder.textView.setText(list.get(position));</span><br><span class="line">    <span class="keyword">return</span> convertView;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>SimpleListAdapter中，实现了抽象方法bindView(…)，并且使用了ListView的缓存机制，但bindView(…)中填充Item视图并没有写死，而是交给了子类DrawerListAdapter去进行实现。</p>
<h4 id="2-7-1-3_DrawerListAdapter"><a href="#2-7-1-3_DrawerListAdapter" class="headerlink" title="2.7.1.3 DrawerListAdapter"></a>2.7.1.3 DrawerListAdapter</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">int</span> <span class="title">getLayout</span><span class="params">()</span> </span>&#123; <span class="keyword">return</span> R.layout.drawer_list_item_layout; &#125;</span><br></pre></td></tr></table></figure>
<h5 id="2-7-1-3-1__u5E03_u5C40"><a href="#2-7-1-3-1__u5E03_u5C40" class="headerlink" title="2.7.1.3.1 布局"></a>2.7.1.3.1 布局</h5><p>布局仅用了一个简洁的TextView，但TextView中包含了几个不常见的属性:<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">android:textAppearance="?android:attr/textAppearanceMedium"</span><br><span class="line">tools:text="Medium Text"</span><br><span class="line">android:singleLine="true"</span><br></pre></td></tr></table></figure></p>
<ul>
<li>android:textAppearance: 系统文字外观，’?’代表试探系统是否有此外观，没有则使用默认外观</li>
<li>tools:text: 告诉Android Studio在运行时忽略该属性，只在设计布局时有效</li>
<li>android:singleLine: 就是单行显示文字</li>
</ul>
<h3 id="2-7-2__u62BD_u5C49_u5F00_u5173_u6309_u94AE"><a href="#2-7-2__u62BD_u5C49_u5F00_u5173_u6309_u94AE" class="headerlink" title="2.7.2 抽屉开关按钮"></a>2.7.2 抽屉开关按钮</h3><p>通过 <code>mDrawerLayout.setDrawerListener(mDrawerToggle);</code> 为抽屉加上开关抽屉的监听。对监听器的配置如下:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">mDrawerToggle = <span class="keyword">new</span> ActionBarDrawerToggle(<span class="keyword">this</span>, mDrawerLayout, <span class="number">0</span>, <span class="number">0</span>)&#123;</span><br><span class="line">    <span class="annotation">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onDrawerOpened</span><span class="params">(View drawerView)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">super</span>.onDrawerOpened(drawerView);</span><br><span class="line">        invalidateOptionsMenu();</span><br><span class="line">        mainPresenter.onDrawerOpened();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="annotation">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onDrawerClosed</span><span class="params">(View drawerView)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">super</span>.onDrawerClosed(drawerView);</span><br><span class="line">        invalidateOptionsMenu();</span><br><span class="line">        mainPresenter.onDrawerClosed();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line">mDrawerToggle.setDrawerIndicatorEnabled(<span class="keyword">true</span>);  <span class="comment">// 指示器: 用于动画展示开关操作按钮变化</span></span><br></pre></td></tr></table></figure></p>
<h3 id="2-7-3__u8BBE_u7F6E_u62BD_u5C49_u906E_u5E18_u989C_u8272"><a href="#2-7-3__u8BBE_u7F6E_u62BD_u5C49_u906E_u5E18_u989C_u8272" class="headerlink" title="2.7.3 设置抽屉遮帘颜色"></a>2.7.3 设置抽屉遮帘颜色</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mDrawerLayout.setScrimColor(getCompactColor(R.color.drawer_scrim_color));</span><br></pre></td></tr></table></figure>
<p>此处放上设置遮帘为蓝色后的效果图:<br><img src="http://7xqdz8.com1.z0.glb.clouddn.com/160411scrim.png" alt="遮帘颜色配置"></p>
<h2 id="2-8_PopupMenu"><a href="#2-8_PopupMenu" class="headerlink" title="2.8 PopupMenu"></a>2.8 PopupMenu</h2><p>在每个CardView上面需要显示菜单，包含”编辑”和”回收”，显示PopupMenu方法如下:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">showNormalPopupMenu</span><span class="params">(View view, SNote note)</span> </span>&#123;</span><br><span class="line">    PopupMenu popup = <span class="keyword">new</span> PopupMenu(<span class="keyword">this</span>, view);</span><br><span class="line">    popup.getMenuInflater()</span><br><span class="line">            .inflate(R.menu.menu_notes_more, popup.getMenu());</span><br><span class="line">    popup.setOnMenuItemClickListener((item -&gt; mainPresenter.onPopupMenuClick(item.getItemId(), note)));</span><br><span class="line">    popup.show();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h2 id="2-9_ActionBar_u4E0A_u7684_u641C_u7D22_u6846"><a href="#2-9_ActionBar_u4E0A_u7684_u641C_u7D22_u6846" class="headerlink" title="2.9 ActionBar上的搜索框"></a>2.9 ActionBar上的搜索框</h2><h3 id="2-9-1__u5B9A_u4E49_u83DC_u5355"><a href="#2-9-1__u5B9A_u4E49_u83DC_u5355" class="headerlink" title="2.9.1 定义菜单"></a>2.9.1 定义菜单</h3><p>首先在menu.xml中新增搜索项:<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">item</span></span><br><span class="line">    <span class="attribute">android:id</span>=<span class="value">"@+id/action_search"</span></span><br><span class="line">    <span class="attribute">android:icon</span>=<span class="value">"@drawable/abc_ic_search_api_mtrl_alpha"</span></span><br><span class="line">    <span class="attribute">android:title</span>=<span class="value">"@string/search"</span></span><br><span class="line">    <span class="attribute">app:showAsAction</span>=<span class="value">"ifRoom|collapseActionView"</span></span><br><span class="line">    <span class="attribute">app:actionViewClass</span>=<span class="value">"android.support.v7.widget.SearchView"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">item</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<h3 id="2-9-2__u521D_u59CB_u5316SearchView"><a href="#2-9-2__u521D_u59CB_u5316SearchView" class="headerlink" title="2.9.2 初始化SearchView"></a>2.9.2 初始化SearchView</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">onCreateOptionsMenu</span><span class="params">(Menu menu)</span> </span>&#123;</span><br><span class="line">    getMenuInflater().inflate(R.menu.menu_main, menu);</span><br><span class="line">    SearchManager searchManager =</span><br><span class="line">            (SearchManager) getSystemService(Context.SEARCH_SERVICE);</span><br><span class="line">    MenuItem searchItem = menu.findItem(R.id.action_search);</span><br><span class="line">    <span class="comment">//searchItem.expandActionView();    // 默认展开搜索框</span></span><br><span class="line">    SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);</span><br><span class="line">    ComponentName componentName = getComponentName();</span><br><span class="line">    searchView.setSearchableInfo(</span><br><span class="line">            searchManager.getSearchableInfo(componentName));</span><br><span class="line">    searchView.setQueryHint(getString(R.string.search_note));</span><br><span class="line">    searchView.setOnQueryTextListener(<span class="keyword">new</span> SearchView.OnQueryTextListener() &#123;</span><br><span class="line">        <span class="annotation">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">onQueryTextSubmit</span><span class="params">(String s)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="annotation">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">onQueryTextChange</span><span class="params">(String s)</span> </span>&#123;</span><br><span class="line">            recyclerAdapter.getFilter().filter(s);  <span class="comment">// 文字改变就即时处理搜索</span></span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br><span class="line">    MenuItemCompat.setOnActionExpandListener(searchItem, mainPresenter);    <span class="comment">// 监听搜索框是否打开，用于隐藏FloatingActionBar和禁用下拉刷新</span></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="2-10__u5904_u7406_u83DC_u5355_u4E8B_u4EF6"><a href="#2-10__u5904_u7406_u83DC_u5355_u4E8B_u4EF6" class="headerlink" title="2.10 处理菜单事件"></a>2.10 处理菜单事件</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">onOptionsItemSelected</span><span class="params">(MenuItem item)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(mDrawerToggle.onOptionsItemSelected(item)) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (mainPresenter.onOptionsItemSelected(item.getItemId()))&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">super</span>.onOptionsItemSelected(item);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>第一个if用于判断是否点击打开抽屉开关按钮，第二个才传入MainPresenter进行菜单的处理，返回true当然就表示消耗此事件。</p>
<h2 id="2-11__u5904_u7406_u5B9E_u4F53_u6309_u952E_u4E8B_u4EF6"><a href="#2-11__u5904_u7406_u5B9E_u4F53_u6309_u952E_u4E8B_u4EF6" class="headerlink" title="2.11 处理实体按键事件"></a>2.11 处理实体按键事件</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">onKeyDown</span><span class="params">(<span class="keyword">int</span> keyCode, KeyEvent event)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> mainPresenter.onKeyDown(keyCode) || <span class="keyword">super</span>.onKeyDown(keyCode, event);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>返回值注意的是先处理传入MainPresentor里面方案，有代码自左至右运行顺序，如果不满足则按父类方法处理，这样写简直精妙，避免了多重if判断。</p>
<h2 id="2-12__u5220_u9664_u5BF9_u8BDD_u6846_u7684_u663E_u793A"><a href="#2-12__u5220_u9664_u5BF9_u8BDD_u6846_u7684_u663E_u793A" class="headerlink" title="2.12 删除对话框的显示"></a>2.12 删除对话框的显示</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">showDeleteForeverDialog</span><span class="params">(<span class="keyword">final</span> SNote note)</span> </span>&#123;</span><br><span class="line">    AlertDialog.Builder builder = DialogUtils.makeDialogBuilder(<span class="keyword">this</span>);</span><br><span class="line">    builder.setTitle(R.string.delete_tip);</span><br><span class="line">    DialogInterface.OnClickListener listener = (DialogInterface dialog, <span class="keyword">int</span> which) -&gt;</span><br><span class="line">            mainPresenter.onDeleteForeverDialogClick(note, which);</span><br><span class="line">    builder.setPositiveButton(R.string.sure, listener);</span><br><span class="line">    builder.setNegativeButton(R.string.cancel, listener);</span><br><span class="line">    builder.show();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>这个逻辑没什么问题，主要想说的就是用lambda表达式的写法真的很好，不过笔者很好奇作者如何这么顺畅地写出lambda表达式，毕竟没有智能提示。</p>
<h2 id="2-13_SnackbarUtils"><a href="#2-13_SnackbarUtils" class="headerlink" title="2.13 SnackbarUtils"></a>2.13 SnackbarUtils</h2><p>SnackbarUtils是作者封装的快速显示Snackbar消息的，这个要学习的是如何通过传入Activity或Fab本身来执行Snackbar.make(…)方法:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">show</span><span class="params">(View view, <span class="keyword">int</span> message)</span> </span>&#123;</span><br><span class="line">    Snackbar.make(view, message, Snackbar.LENGTH_SHORT)</span><br><span class="line">            .show();</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">show</span><span class="params">(Activity activity, <span class="keyword">int</span> message)</span> </span>&#123;</span><br><span class="line">    View view = activity.getWindow().getDecorView();</span><br><span class="line">    show(view, message);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>可以传入FloatActionBar本身调用方法:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SnackbarUtils.show(fab, message);</span><br></pre></td></tr></table></figure></p>
<p>至此，庞大的MainActivity算是分析得差不多了，那么接下来便啃另一块大骨头——MainPresenter。</p>
<h1 id="3-_Presenter__u2014_u2014_MVP_u4E2D_u7684_u6865_u6881"><a href="#3-_Presenter__u2014_u2014_MVP_u4E2D_u7684_u6865_u6881" class="headerlink" title="3. Presenter —— MVP中的桥梁"></a>3. Presenter —— MVP中的桥梁</h1><h2 id="3-1__u63A5_u53E3"><a href="#3-1__u63A5_u53E3" class="headerlink" title="3.1 接口"></a>3.1 接口</h2><p>为了将逻辑放到P层中，MainPresenter继承了多个接口。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MainPresenter</span> <span class="keyword">implements</span> <span class="title">Presenter</span>, <span class="title">android</span>.<span class="title">view</span>.<span class="title">View</span>.<span class="title">OnClickListener</span>, <span class="title">SwipeRefreshLayout</span>.<span class="title">OnRefreshListener</span>,</span><br><span class="line">        <span class="title">PopupMenu</span>.<span class="title">OnMenuItemClickListener</span>, <span class="title">MenuItemCompat</span>.<span class="title">OnActionExpandListener</span> </span>&#123;</span><br></pre></td></tr></table></figure></p>
<p>由于其它接口前文已有提及，此处只展示和分析Presenter接口。<br>Presenter接口将Activity的生命周期抽象出来，并且通过attachView将Activity传入，用于MainPresenter的初始化。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Presenter</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">onCreate</span> <span class="params">(Bundle savedInstanceState)</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">onResume</span><span class="params">()</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">onStart</span> <span class="params">()</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">onPause</span><span class="params">()</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">onStop</span> <span class="params">()</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">onDestroy</span><span class="params">()</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">attachView</span><span class="params">(View v)</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<blockquote>
<p>注意View是本项目中所定义的，并非安卓API。</p>
</blockquote>
<h2 id="3-2__u6784_u9020_u51FD_u6570"><a href="#3-2__u6784_u9020_u51FD_u6570" class="headerlink" title="3.2 构造函数"></a>3.2 构造函数</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Inject</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">MainPresenter</span><span class="params">(@ContextLifeCycle (<span class="string">"Activity"</span>)</span>Context context, FinalDb finalDb, PreferenceUtils preferenceUtils,</span><br><span class="line">                     ObservableUtils mObservableUtils, EverNoteUtils everNoteUtils) </span>&#123;</span><br><span class="line">    <span class="keyword">this</span>.mContext = context;</span><br><span class="line">    <span class="keyword">this</span>.mFinalDb = finalDb;</span><br><span class="line">    <span class="keyword">this</span>.mPreferenceUtils = preferenceUtils;</span><br><span class="line">    <span class="keyword">this</span>.mEverNoteUtils = everNoteUtils;</span><br><span class="line">    <span class="keyword">this</span>.mObservableUtils = mObservableUtils;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>构造函数的第一个参数前有一个 <code>@ContextLifeCycle (&quot;Activity&quot;)</code> ，不知道读者是否对此感到疑惑，要分析这个首先要了解java中的自定义注解。</p>
<h3 id="3-2-1_Java_Annotation_u81EA_u5B9A_u4E49_u6CE8_u89E3"><a href="#3-2-1_Java_Annotation_u81EA_u5B9A_u4E49_u6CE8_u89E3" class="headerlink" title="3.2.1 Java Annotation自定义注解"></a>3.2.1 Java Annotation自定义注解</h3><p>此处只提及几个关键点，读者感兴趣可以参考<a href="http://josh-persistence.iteye.com/blog/2226493" target="_blank" rel="external">深入浅出Java Annotation(元注解和自定义注解）</a>。</p>
<h4 id="3-2-1-1_Annotation_u6982_u8FF0"><a href="#3-2-1-1_Annotation_u6982_u8FF0" class="headerlink" title="3.2.1.1 Annotation概述"></a>3.2.1.1 Annotation概述</h4><p>Annontation是Java5开始引入的新特征。中文名称一般叫注解。它提供了一种安全的类似注释的机制，用来将任何的信息或元数据（metadata）与程序元素（类、方法、成员变量等）进行关联。</p>
<h4 id="3-2-1-2__u5B9A_u4E49Annotation"><a href="#3-2-1-2__u5B9A_u4E49Annotation" class="headerlink" title="3.2.1.2 定义Annotation"></a>3.2.1.2 定义Annotation</h4><ul>
<li>使用关键字@interface而不是interface</li>
<li>方法定义Annotation的成员，方法返回值类型必须为primitive类型、Class类型、枚举类型、annotation类型或者由前面类型之一作为元素的一维数组，方法的后面可以使用 default和一个默认数值来声明成员的默认值，null不能作为成员默认值</li>
</ul>
<h4 id="3-2-1-3__u5143_u6CE8_u89E3"><a href="#3-2-1-3__u5143_u6CE8_u89E3" class="headerlink" title="3.2.1.3 元注解"></a>3.2.1.3 元注解</h4><ol>
<li>@Target 所修饰的对象范围</li>
<li>@Retention 该Annotation被保留的时间长短</li>
<li>@Documented 可以被例如javadoc此类的工具文档化</li>
<li>@Inherited 被标注的类型是被继承的</li>
</ol>
<h4 id="3-2-1-4__u81EA_u5B9A_u4E49_u6CE8_u89E3"><a href="#3-2-1-4__u81EA_u5B9A_u4E49_u6CE8_u89E3" class="headerlink" title="3.2.1.4 自定义注解"></a>3.2.1.4 自定义注解</h4><p>定义注解格式：<br>　　public @interface 注解名 {定义体}<br>例如:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Retention</span>(RetentionPolicy.RUNTIME)  </span><br><span class="line"><span class="annotation">@Target</span>(ElementType.TYPE)  </span><br><span class="line"><span class="annotation">@Documented</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="annotation">@interface</span> Description &#123;  </span><br><span class="line">    <span class="function">String <span class="title">value</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h4 id="3-2-1-5__u5BF9_u9879_u76EE_u4E2D_u201DContextLifeCycle_u201D_u7684_u5206_u6790"><a href="#3-2-1-5__u5BF9_u9879_u76EE_u4E2D_u201DContextLifeCycle_u201D_u7684_u5206_u6790" class="headerlink" title="3.2.1.5 对项目中”ContextLifeCycle”的分析"></a>3.2.1.5 对项目中”ContextLifeCycle”的分析</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Qualifier</span></span><br><span class="line"><span class="annotation">@Documented</span></span><br><span class="line"><span class="annotation">@Retention</span>(RUNTIME)</span><br><span class="line"><span class="keyword">public</span> <span class="annotation">@interface</span> ContextLifeCycle &#123;</span><br><span class="line">    <span class="function">String <span class="title">value</span><span class="params">()</span> <span class="keyword">default</span> "App"</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>@Qualifier: 限定注释符<br>因为ContextLifeCycle的实现需要反射，所以我们暂时不能跟踪到它的实现，所以暂时先不作实现分析。</p>
<h3 id="3-2-2_FinalDb_u53C2_u6570"><a href="#3-2-2_FinalDb_u53C2_u6570" class="headerlink" title="3.2.2 FinalDb参数"></a>3.2.2 FinalDb参数</h3><p>FinalDb是一个比较庞大的类，是aFinal第三方库的一个子模块，主要是数据库操作，接下来让我们大致了解一下它。</p>
<h4 id="3-2-2-1__u6570_u636E_u5E93_u8FDE_u63A5_u6C60"><a href="#3-2-2-1__u6570_u636E_u5E93_u8FDE_u63A5_u6C60" class="headerlink" title="3.2.2.1 数据库连接池"></a>3.2.2.1 数据库连接池</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> HashMap&lt;String, FinalDb&gt; daoMap = <span class="keyword">new</span> HashMap&lt;String, FinalDb&gt;();</span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">synchronized</span> <span class="keyword">static</span> FinalDb <span class="title">getInstance</span><span class="params">(DaoConfig daoConfig)</span> </span>&#123;</span><br><span class="line">	FinalDb dao = daoMap.get(daoConfig.getDbName());</span><br><span class="line">	<span class="keyword">if</span> (dao == <span class="keyword">null</span>) &#123;</span><br><span class="line">		dao = <span class="keyword">new</span> FinalDb(daoConfig);</span><br><span class="line">		daoMap.put(daoConfig.getDbName(), dao);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> dao;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>由HashMap类型的daoMap成员变量和getInstance(…)，可以看出将daoMap作为数据库连接池使用，可以提高数据库连接的复用率，不过注意getInstance()也是私有的，获取FinalDb要通过create()方法。</p>
<h5 id="3-2-2-1-1__u6570_u636E_u5E93_u4FE1_u606F_u914D_u7F6E_u7C7BDaoConfig"><a href="#3-2-2-1-1__u6570_u636E_u5E93_u4FE1_u606F_u914D_u7F6E_u7C7BDaoConfig" class="headerlink" title="3.2.2.1.1 数据库信息配置类DaoConfig"></a>3.2.2.1.1 数据库信息配置类DaoConfig</h5><p>DaoConfig主要包含以下属性:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> Context mContext = <span class="keyword">null</span>; <span class="comment">// android上下文</span></span><br><span class="line"><span class="keyword">private</span> String mDbName = <span class="string">"notes.db"</span>; <span class="comment">// 数据库名字</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">int</span> dbVersion = <span class="number">1</span>; <span class="comment">// 数据库版本</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">boolean</span> debug = <span class="keyword">true</span>; <span class="comment">// 是否是调试模式（调试模式 增删改查的时候显示SQL语句）</span></span><br><span class="line"><span class="keyword">private</span> DbUpdateListener dbUpdateListener;</span><br><span class="line"><span class="comment">// private boolean saveOnSDCard = false;//是否保存到SD卡</span></span><br><span class="line"><span class="keyword">private</span> String targetDirectory;<span class="comment">// 数据库文件在sd卡中的目录</span></span><br></pre></td></tr></table></figure></p>
<h4 id="3-2-2-2__u6784_u9020_u51FD_u6570"><a href="#3-2-2-2__u6784_u9020_u51FD_u6570" class="headerlink" title="3.2.2.2 构造函数"></a>3.2.2.2 构造函数</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="title">FinalDb</span><span class="params">(DaoConfig config)</span> </span>&#123;</span><br><span class="line">	...</span><br><span class="line">	<span class="keyword">if</span> (config.getTargetDirectory() != <span class="keyword">null</span></span><br><span class="line">			&amp;&amp; config.getTargetDirectory().trim().length() &gt; <span class="number">0</span>) &#123;</span><br><span class="line">		<span class="keyword">this</span>.db = createDbFileOnSDCard(config.getTargetDirectory(),</span><br><span class="line">				config.getDbName());</span><br><span class="line">	&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">		<span class="keyword">this</span>.db = <span class="keyword">new</span> SqliteDbHelper(config.getContext()</span><br><span class="line">				.getApplicationContext(), config.getDbName(),</span><br><span class="line">				config.getDbVersion(), config.getDbUpdateListener())</span><br><span class="line">				.getWritableDatabase();</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">this</span>.config = config;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>此部分判断如果配置中指定了文件目录，则在指定的文件目录创建数据库文件，否则使用SqliteDbHelper获取软件Data目录下的数据库。</p>
<h5 id="3-2-2-2-1_createDbFileOnSDCard_u65B9_u6CD5"><a href="#3-2-2-2-1_createDbFileOnSDCard_u65B9_u6CD5" class="headerlink" title="3.2.2.2.1 createDbFileOnSDCard方法"></a>3.2.2.2.1 createDbFileOnSDCard方法</h5><p>通过SQLiteDatabase.openOrCreateDatabase(file, null)在SD卡创建数据库文件(*.db)。</p>
<h5 id="3-2-2-2-2_SqliteDbHelper_u5185_u90E8_u7C7B"><a href="#3-2-2-2-2_SqliteDbHelper_u5185_u90E8_u7C7B" class="headerlink" title="3.2.2.2.2 SqliteDbHelper内部类"></a>3.2.2.2.2 SqliteDbHelper内部类</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SqliteDbHelper</span> <span class="keyword">extends</span> <span class="title">SQLiteOpenHelper</span> </span>&#123;</span><br><span class="line">    ...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>此类继承SQLiteOpenHelper获取安卓默认的数据库。</p>
<h4 id="3-2-2-3__u516C_u6709_u7684create_28_29_u65B9_u6CD5"><a href="#3-2-2-3__u516C_u6709_u7684create_28_29_u65B9_u6CD5" class="headerlink" title="3.2.2.3 公有的create()方法"></a>3.2.2.3 公有的create()方法</h4><p>create方法重载了多个，配合使用一个或多个参数调用的情况。例如其中之一:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> FinalDb <span class="title">create</span><span class="params">(Context context, String targetDirectory,</span><br><span class="line">		String dbName, <span class="keyword">boolean</span> isDebug, <span class="keyword">int</span> dbVersion,</span><br><span class="line">		DbUpdateListener dbUpdateListener)</span> </span>&#123;</span><br><span class="line">	DaoConfig config = <span class="keyword">new</span> DaoConfig();</span><br><span class="line">	config.setContext(context);</span><br><span class="line">	config.setTargetDirectory(targetDirectory);</span><br><span class="line">	config.setDbName(dbName);</span><br><span class="line">	config.setDebug(isDebug);</span><br><span class="line">	config.setDbVersion(dbVersion);</span><br><span class="line">	config.setDbUpdateListener(dbUpdateListener);</span><br><span class="line">	<span class="keyword">return</span> create(config);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>后面便是对数据库CRUD操作和数据库关系操作，笔者能力有限，便不继续研读，接下来谈谈此框架的使用方法。</p>
<h4 id="3-2-2-4__u7528_u6CD5"><a href="#3-2-2-4__u7528_u6CD5" class="headerlink" title="3.2.2.4 用法"></a>3.2.2.4 用法</h4><ul>
<li><p>首先创建相关Entity类，如:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">User</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> id;</span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line">    <span class="keyword">private</span> String email;</span><br><span class="line">    <span class="keyword">private</span> Date registerDate;</span><br><span class="line">    <span class="keyword">private</span> Double money;</span><br><span class="line">     </span><br><span class="line">    <span class="comment">/////////////getter and setter 不能省略哦///////////////</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getId</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> id;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setId</span><span class="params">(<span class="keyword">int</span> id)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.id = id;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getName</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> name;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setName</span><span class="params">(String name)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getEmail</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> email;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setEmail</span><span class="params">(String email)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.email = email;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> Date <span class="title">getRegisterDate</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> registerDate;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setRegisterDate</span><span class="params">(Date registerDate)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.registerDate = registerDate;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> Double <span class="title">getMoney</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> money;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setMoney</span><span class="params">(Double money)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.money = money;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p>接下来使用aFinal即可</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">FinalDb db = FinalDb.create(<span class="keyword">this</span>);</span><br><span class="line">User user = <span class="keyword">new</span> User();</span><br><span class="line">user.setEmail(<span class="string">"..."</span>);</span><br><span class="line">user.setName(<span class="string">"..."</span>);</span><br><span class="line">user.setRegisterDate(<span class="keyword">new</span> Date());</span><br><span class="line">db.save(user);</span><br><span class="line">List&lt;User&gt; userList = db.findAll(User.class); <span class="comment">//查询所有的用户</span></span><br><span class="line">Log.e(<span class="string">"AfinalOrmDemoActivity"</span>, <span class="string">"用户数量："</span>+ (userList!=<span class="keyword">null</span>?userList.size():<span class="number">0</span>));</span><br><span class="line">textView.setText(userList.get(<span class="number">0</span>).getName()+<span class="string">":"</span>+user.getRegisterDate());</span><br></pre></td></tr></table></figure>
</li>
</ul>
<p>至此，相信读者对FinalDb有了一个初步的认识。</p>
<h3 id="3-2-3_PreferenceUtils_u53C2_u6570"><a href="#3-2-3_PreferenceUtils_u53C2_u6570" class="headerlink" title="3.2.3 PreferenceUtils参数"></a>3.2.3 PreferenceUtils参数</h3><p>这是一个对SharePreference的封装类，比较简单，就不做分析了。</p>
<h3 id="3-2-4_ObservableUtils_u53C2_u6570"><a href="#3-2-4_ObservableUtils_u53C2_u6570" class="headerlink" title="3.2.4 ObservableUtils参数"></a>3.2.4 ObservableUtils参数</h3><p>ObservableUtils采用了RxJava，作为被观察者，这其中有一点比较重要——将函数作为参数来传递，这是C#的一个特性——委托，亦或是代理设计模式。</p>
<h4 id="3-2-4-1_Fun_u63A5_u53E3"><a href="#3-2-4-1_Fun_u63A5_u53E3" class="headerlink" title="3.2.4.1 Fun接口"></a>3.2.4.1 Fun<t>接口</t></h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Fun</span>&lt;<span class="title">T</span>&gt; </span>&#123;</span><br><span class="line">    <span class="function">T <span class="title">call</span><span class="params">()</span> <span class="keyword">throws</span> Exception</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>内部包含一个Fun接口，即为一个函数，每个需要作为参数的函数被包装在实现该接口的类中。如:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="class"><span class="keyword">class</span> <span class="title">GetEverNoteUserFun</span> <span class="keyword">implements</span> <span class="title">Fun</span>&lt;<span class="title">User</span>&gt;</span>&#123;</span><br><span class="line">    <span class="keyword">private</span> EverNoteUtils mEverNoteUtils;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">GetEverNoteUserFun</span><span class="params">(EverNoteUtils mEverNoteUtils)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.mEverNoteUtils = mEverNoteUtils;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="annotation">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> User <span class="title">call</span><span class="params">()</span> <span class="keyword">throws</span> Exception</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> mEverNoteUtils.getUser();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>这样函数就能作为一个参数被传递到其它函数中。如:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">create(<span class="keyword">new</span> GetEverNoteUserFun(everNoteUtils))</span><br></pre></td></tr></table></figure></p>
<blockquote>
<p>此处将 <code>方法</code> 称作 <code>函数</code> 是为了便于理解。</p>
</blockquote>
<h3 id="3-2-5_EverNoteUtils_u53C2_u6570"><a href="#3-2-5_EverNoteUtils_u53C2_u6570" class="headerlink" title="3.2.5 EverNoteUtils参数"></a>3.2.5 EverNoteUtils参数</h3><p>EverNoteUtils就是调用印象笔记的API，包含推送笔记和获取笔记等方法，这里可以看印象笔记官方提供的API，此处不作分析。</p>
<!--part 2-->
<h2 id="3-3_onCreate_28_29_u65B9_u6CD5"><a href="#3-3_onCreate_28_29_u65B9_u6CD5" class="headerlink" title="3.3 onCreate()方法"></a>3.3 onCreate()方法</h2><h3 id="3-3-1_Activity_u5D29_u6E83_u7684_u4FE1_u606F_u4FDD_u5B58"><a href="#3-3-1_Activity_u5D29_u6E83_u7684_u4FE1_u606F_u4FDD_u5B58" class="headerlink" title="3.3.1 Activity崩溃的信息保存"></a>3.3.1 Activity崩溃的信息保存</h3><p>想要在Activity崩溃的时候，其实主要是屏幕发生旋转时保存信息，以便重启Activity后能够恢复信息，需要怎么做呢？很简单，重写 <code>onSaveInstanceState(Bundle outState)</code> 方法，在内部实现信息的保存，并在onCreate方法中对信息进行恢复即可，如:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 信息的保存: 笔者猜测是用于保存当前界面，保存在"Normal"模式还是"回收站"模式</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onSaveInstanceState</span><span class="params">(Bundle outState)</span></span>&#123;</span><br><span class="line">    outState.putInt(CURRENT_NOTE_TYPE_KEY, mCurrentNoteTypePage.getValue());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>然后再onCreate中恢复信息:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (savedInstanceState != <span class="keyword">null</span>)&#123;</span><br><span class="line">    <span class="keyword">int</span> value = savedInstanceState.getInt(CURRENT_NOTE_TYPE_KEY);</span><br><span class="line">    mCurrentNoteTypePage = SNote.NoteType.mapValueToStatus(value);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h3 id="3-3-2__u521D_u59CB_u5316_u89C6_u56FE"><a href="#3-3-2__u521D_u59CB_u5316_u89C6_u56FE" class="headerlink" title="3.3.2 初始化视图"></a>3.3.2 初始化视图</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">view.initToolbar();</span><br><span class="line">initDrawer();</span><br><span class="line">initMenuGravity();</span><br><span class="line">initItemLayoutManager();</span><br><span class="line">initRecyclerView();</span><br></pre></td></tr></table></figure>
<p>在onCreate方法中还进行了各视图的初始化。</p>
<h4 id="3-3-2-1_initToolbar"><a href="#3-3-2-1_initToolbar" class="headerlink" title="3.3.2.1 initToolbar"></a>3.3.2.1 initToolbar</h4><p>调用所有继承自MainView接口的Activity的初始化Toolbar方法以初始化。</p>
<h4 id="3-3-2-2__u521D_u59CB_u5316_u62BD_u5C49"><a href="#3-3-2-2__u521D_u59CB_u5316_u62BD_u5C49" class="headerlink" title="3.3.2.2 初始化抽屉"></a>3.3.2.2 初始化抽屉</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">drawerList = Arrays.asList(mContext.getResources()</span><br><span class="line">        .getStringArray(R.array.drawer_content));</span><br><span class="line">view.initDrawerView(drawerList);</span><br><span class="line">view.setDrawerItemChecked(mCurrentNoteTypePage.getValue());</span><br><span class="line">view.setToolbarTitle(drawerList.get(mCurrentNoteTypePage.getValue()));</span><br></pre></td></tr></table></figure>
<p>这里值得留意的是在strings.xml中定义数组:<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">array</span> <span class="attribute">name</span>=<span class="value">"drawer_content"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">item</span>&gt;</span>SNotes<span class="tag">&lt;/<span class="title">item</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">item</span>&gt;</span>回收站<span class="tag">&lt;/<span class="title">item</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">array</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<h4 id="3-3-2-3__u8BBE_u7F6E_u62BD_u5C49_u65B9_u5411"><a href="#3-3-2-3__u8BBE_u7F6E_u62BD_u5C49_u65B9_u5411" class="headerlink" title="3.3.2.3 设置抽屉方向"></a>3.3.2.3 设置抽屉方向</h4><p><img src="http://7xqdz8.com1.z0.glb.clouddn.com/160413drawright.png" alt="抽屉居右效果"><br>通过view.setMenuGravity(Gravity.END)和view.setMenuGravity(Gravity.START)设置抽屉的方向，由MVP模式，具体的实现放在MainActivity中。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setMenuGravity</span><span class="params">(<span class="keyword">int</span> gravity)</span> </span>&#123;</span><br><span class="line">    DrawerLayout.LayoutParams params = (DrawerLayout.LayoutParams) drawerRootView.getLayoutParams();</span><br><span class="line">    params.gravity = gravity;</span><br><span class="line">    drawerRootView.setLayoutParams(params);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h4 id="3-3-2-4__u8BBE_u7F6ERecyclerView_u7EBF_u6027_u6216_u7F51_u683C_u6392_u5217"><a href="#3-3-2-4__u8BBE_u7F6ERecyclerView_u7EBF_u6027_u6216_u7F51_u683C_u6392_u5217" class="headerlink" title="3.3.2.4 设置RecyclerView线性或网格排列"></a>3.3.2.4 设置RecyclerView线性或网格排列</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">switchItemLayoutManager</span><span class="params">(<span class="keyword">boolean</span> card)</span></span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (card)&#123;</span><br><span class="line">        view.setLayoutManager(<span class="keyword">new</span> StaggeredGridLayoutManager(<span class="number">2</span>, LinearLayoutManager.VERTICAL));</span><br><span class="line">    &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">        view.setLayoutManager(<span class="keyword">new</span> LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, <span class="keyword">false</span>));</span><br><span class="line">    &#125;</span><br><span class="line">    isCardItemLayout = card;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>在MainActivity中进行视图操作:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">recyclerView.setLayoutManager(manager);</span><br></pre></td></tr></table></figure></p>
<h4 id="3-3-2-5__u52A0_u8F7D_u7B14_u8BB0"><a href="#3-3-2-5__u52A0_u8F7D_u7B14_u8BB0" class="headerlink" title="3.3.2.5 加载笔记"></a>3.3.2.5 加载笔记</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">initRecyclerView</span><span class="params">()</span></span>&#123;</span><br><span class="line">    view.showProgressWheel(<span class="keyword">true</span>);</span><br><span class="line">    mObservableUtils.getLocalNotesByType(mFinalDb, mCurrentNoteTypePage.getValue())</span><br><span class="line">            .subscribeOn(Schedulers.computation())</span><br><span class="line">            .observeOn(AndroidSchedulers.mainThread())</span><br><span class="line">            .subscribe((notes) -&gt; &#123;</span><br><span class="line">                view.initRecyclerView(notes);</span><br><span class="line">                view.showProgressWheel(<span class="keyword">false</span>);</span><br><span class="line">            &#125;, (e) -&gt; &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">                view.showProgressWheel(<span class="keyword">false</span>);</span><br><span class="line">            &#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>这段代码又用到RxJava，所以显得比较复杂，我们来慢慢分析。</p>
<h5 id="3-3-2-5-1_getLocalNotesByType"><a href="#3-3-2-5-1_getLocalNotesByType" class="headerlink" title="3.3.2.5.1 getLocalNotesByType"></a>3.3.2.5.1 getLocalNotesByType</h5><p>那么首先来看ObservableUtils里的getLocalNotesByType方法，它将返回一个Observable对象，此处截取了关键部分:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">return</span> Observable.create(<span class="keyword">new</span> Observable.OnSubscribe&lt;T&gt;() &#123;</span><br><span class="line">    <span class="annotation">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">call</span><span class="params">(Subscriber&lt;? <span class="keyword">super</span> T&gt; subscriber)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            T t = fun.call();</span><br><span class="line">            subscriber.onNext(t);</span><br><span class="line">        &#125;<span class="keyword">catch</span> (Exception e)&#123;</span><br><span class="line">            subscriber.onError(e);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></p>
<p>下面是fun.call():<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> List&lt;SNote&gt; <span class="title">call</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> mFinalDb.findAllByWhere(SNote.class, <span class="string">"type = "</span> + type, <span class="string">"lastOprTime"</span>, <span class="keyword">true</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>其中type为mCurrentNoteTypePage.getValue()，标志是否为回收站的内容。<br>findAllByWhere方法原型为:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">List&lt;T&gt; <span class="title">findAllByWhere</span><span class="params">(Class&lt;T&gt; clazz, String strWhere, String orderBy, <span class="keyword">boolean</span> desc)</span></span>;</span><br></pre></td></tr></table></figure></p>
<p>它是aFinal库中FinalDb中的方法，功能为依据条件查找所有元素并反序列化为对象List。</p>
<h5 id="3-3-2-5-2__u6307_u5B9A_u7EBF_u7A0B"><a href="#3-3-2-5-2__u6307_u5B9A_u7EBF_u7A0B" class="headerlink" title="3.3.2.5.2 指定线程"></a>3.3.2.5.2 指定线程</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">.subscribeOn(Schedulers.computation())</span><br><span class="line">.observeOn(AndroidSchedulers.mainThread())</span><br></pre></td></tr></table></figure>
<p>此处的代码用于指定观察者和被观察者所在的线程，由于加载笔记属于重大任务，所以指定在computation计算线程，另外subscribeOn可指定的参数如图:<br><img src="http://7xqdz8.com1.z0.glb.clouddn.com/160413schedulers.png" alt="可指定的线程"><br>此处回顾一下RxJava的调度器:</p>
<blockquote>
<p>在RxJava 中，Scheduler ——调度器，相当于线程控制器，RxJava 通过它来指定每一段代码应该运行在什么样的线程。RxJava 已经内置了几个 Scheduler ，它们已经适合大多数的使用场景:</p>
<ul>
<li>Schedulers.immediate(): 直接在当前线程运行，相当于不指定线程。这是默认的 Scheduler。</li>
<li>Schedulers.newThread(): 总是启用新线程，并在新线程执行操作。</li>
<li>Schedulers.io(): I/O 操作（读写文件、读写数据库、网络信息交互等）所使用的 Scheduler。行为模式和 newThread() 差不多，区别在于 io() 的内部实现是是用一个无数量上限的线程池，可以重用空闲的线程，因此多数情况下 io() 比 newThread() 更有效率。不要把计算工作放在 io() 中，可以避免创建不必要的线程。</li>
<li>Schedulers.computation(): 计算所使用的 Scheduler。这个计算指的是 CPU 密集型计算，即不会被 I/O 等操作限制性能的操作，例如图形的计算。这个 Scheduler 使用的固定的线程池，大小为 CPU 核数。不要把 I/O 操作放在 computation() 中，否则 I/O 操作的等待时间会浪费 CPU。</li>
<li>另外， Android 还有一个专用的 AndroidSchedulers.mainThread()，它指定的操作将在 Android 主线程运行。</li>
</ul>
</blockquote>
<h5 id="3-3-2-5-3__u8BA2_u9605"><a href="#3-3-2-5-3__u8BA2_u9605" class="headerlink" title="3.3.2.5.3 订阅"></a>3.3.2.5.3 订阅</h5><p>subscribe(onNext, onError)方法需要两个参数，一个是接下来需要执行的操作，一个是执行错误的回调操作，均需要实现Action1接口，此处使用lambda表达式简化了代码。</p>
<h3 id="3-3-3_EventBus_u5E93"><a href="#3-3-3_EventBus_u5E93" class="headerlink" title="3.3.3 EventBus库"></a>3.3.3 EventBus库</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">EventBus.getDefault().register(<span class="keyword">this</span>);</span><br></pre></td></tr></table></figure>
<p>接下来使用到了 <code>EventBus</code> 库，所以让我们先来学习一下EventBus，这个库真可以说是发现的一块新大陆。</p>
<h4 id="3-3-3-1__u4ECB_u7ECD"><a href="#3-3-3-1__u4ECB_u7ECD" class="headerlink" title="3.3.3.1 介绍"></a>3.3.3.1 介绍</h4><p>EventBus是一款针对Android优化的发布/订阅事件总线。主要功能是替代Intent,Handler,BroadCast在Fragment，Activity，Service，线程之间传递消息.优点是开销小，代码更优雅。以及将发送者和接收者解耦。</p>
<h4 id="3-3-3-2__u4F7F_u7528"><a href="#3-3-3-2__u4F7F_u7528" class="headerlink" title="3.3.3.2 使用"></a>3.3.3.2 使用</h4><ul>
<li><p>导入库</p>
<figure class="highlight gradle"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">compile</span> <span class="string">'org.greenrobot:eventbus:3.0.0'</span></span><br></pre></td></tr></table></figure>
</li>
<li><p>编写消息类，传递的消息是一个对象</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">FirstEvent</span> </span>&#123;</span><br><span class="line">  </span><br><span class="line">    <span class="keyword">private</span> String mMsg;  </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">FirstEvent</span><span class="params">(String msg)</span> </span>&#123;</span><br><span class="line">        mMsg = msg;  </span><br><span class="line">    &#125;  </span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getMsg</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> mMsg;  </span><br><span class="line">    &#125;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p>注册与反注册<br>在onCreate方法中进行注册:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">EventBus.getDefault().register(<span class="keyword">this</span>);</span><br></pre></td></tr></table></figure>
</li>
</ul>
<p>在onDestroy方法中进行反注册:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">EventBus.getDefault().unregister(<span class="keyword">this</span>);</span><br></pre></td></tr></table></figure></p>
<ul>
<li><p>发送消息</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">EventBus.getDefault().post(<span class="keyword">new</span> FirstEvent(<span class="string">"FirstEvent btn clicked"</span>));</span><br></pre></td></tr></table></figure>
</li>
<li><p>接收消息<br>在接受消息的Activity中重写事件接收方法，如onEventMainThread:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onEventMainThread</span><span class="params">(FirstEvent event)</span></span>;</span><br></pre></td></tr></table></figure>
</li>
</ul>
<blockquote>
<p>注参数一定要匹配，否则该方法将接收不到数据。消息的接收是通过判断参数是否匹配来的，它将调用四种接收方法中所有匹配该参数的方法。</p>
</blockquote>
<h4 id="3-3-3-3_4_u79CD_u63A5_u6536_u6D88_u606F_u65B9_u6CD5"><a href="#3-3-3-3_4_u79CD_u63A5_u6536_u6D88_u606F_u65B9_u6CD5" class="headerlink" title="3.3.3.3 4种接收消息方法"></a>3.3.3.3 4种接收消息方法</h4><p>前文在接受消息使用到是onEventMainThread方法，那么各方法有什么区别呢。</p>
<ul>
<li>onEvent:如果使用onEvent作为订阅函数，那么该事件在哪个线程发布出来的，onEvent就会在这个线程中运行，也就是说发布事件和接收事件线程在同一个线程。使用这个方法时，在onEvent方法中不能执行耗时操作，如果执行耗时操作容易导致事件分发延迟。</li>
<li>onEventMainThread:如果使用onEventMainThread作为订阅函数，那么不论事件是在哪个线程中发布出来的，onEventMainThread都会在UI线程中执行，接收事件就会在UI线程中运行，这个在Android中是非常有用的，因为在Android中只能在UI线程中跟新UI，所以在onEvnetMainThread方法中是不能执行耗时操作的。</li>
<li>onEventBackground:如果使用onEventBackgrond作为订阅函数，那么如果事件是在UI线程中发布出来的，那么onEventBackground就会在子线程中运行，如果事件本来就是子线程中发布出来的，那么onEventBackground函数直接在该子线程中执行。</li>
<li>onEventAsync：使用这个函数作为订阅函数，那么无论事件在哪个线程发布，都会创建新的子线程在执行onEventAsync.</li>
</ul>
<p>至此，EventBus的使用已基本介绍完毕，接下来分析EventBus在本项目中的使用。</p>
<h4 id="3-3-3-3__u672C_u9879_u76EE_u4E2DEventBus_u4F7F_u7528"><a href="#3-3-3-3__u672C_u9879_u76EE_u4E2DEventBus_u4F7F_u7528" class="headerlink" title="3.3.3.3 本项目中EventBus使用"></a>3.3.3.3 本项目中EventBus使用</h4><h4 id="3-3-3-3-1__u6CE8_u518C_u4E0E_u53CD_u6CE8_u518C"><a href="#3-3-3-3-1__u6CE8_u518C_u4E0E_u53CD_u6CE8_u518C" class="headerlink" title="3.3.3.3.1 注册与反注册"></a>3.3.3.3.1 注册与反注册</h4><p>首先在onCreate和onDestroy中进行了注册与反注册。</p>
<h4 id="3-3-3-3-2__u6D88_u606F_u63A5_u6536_u2014_u2014_u540C_u6B65_u7B14_u8BB0"><a href="#3-3-3-3-2__u6D88_u606F_u63A5_u6536_u2014_u2014_u540C_u6B65_u7B14_u8BB0" class="headerlink" title="3.3.3.3.2 消息接收——同步笔记"></a>3.3.3.3.2 消息接收——同步笔记</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onEventMainThread</span><span class="params">(EverNoteUtils.SyncResult result)</span></span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (result != EverNoteUtils.SyncResult.START)</span><br><span class="line">        view.stopRefresh();</span><br><span class="line">    <span class="keyword">switch</span> (result)&#123;</span><br><span class="line">        <span class="keyword">case</span> ERROR_NOT_LOGIN: view.showGoBindEverNoteSnackbar(R.string.unbind_ever_note_tip, R.string.go_bind);<span class="keyword">break</span>;</span><br><span class="line">        ...</span><br><span class="line">        <span class="keyword">case</span> SUCCESS:view.showSnackbar(R.string.sync_success);refreshNoteTypePage();<span class="keyword">break</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>消息接收方法处于主线程中，可以进行UI操作，同时，消息的参数很巧妙——使用了一个枚举，作为参数，可以集合多种情况。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">enum</span> SyncResult&#123;</span><br><span class="line">    START,</span><br><span class="line">    ...</span><br><span class="line">    SUCCESS</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h4 id="3-3-3-3-3__u6D88_u606F_u63A5_u6536_u2014_u2014_u5176_u4ED6_u64CD_u4F5C"><a href="#3-3-3-3-3__u6D88_u606F_u63A5_u6536_u2014_u2014_u5176_u4ED6_u64CD_u4F5C" class="headerlink" title="3.3.3.3.3 消息接收——其他操作"></a>3.3.3.3.3 消息接收——其他操作</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onEventMainThread</span><span class="params">(NotifyEvent event)</span></span>&#123;</span><br><span class="line">    <span class="keyword">switch</span> (event.getType())&#123;</span><br><span class="line">        <span class="keyword">case</span> NotifyEvent.REFRESH_LIST:</span><br><span class="line">            view.startRefresh();</span><br><span class="line">            onRefresh();</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        <span class="keyword">case</span> NotifyEvent.CREATE_NOTE:</span><br><span class="line">            <span class="keyword">if</span> (event.getData() <span class="keyword">instanceof</span> SNote)&#123;</span><br><span class="line">                SNote note = (SNote)event.getData();</span><br><span class="line">                view.addNote(note);</span><br><span class="line">                view.scrollRecyclerViewToTop();</span><br><span class="line">                pushNote(note);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        <span class="keyword">case</span> NotifyEvent.UPDATE_NOTE:</span><br><span class="line">            <span class="keyword">if</span> (event.getData() <span class="keyword">instanceof</span> SNote)&#123;</span><br><span class="line">                SNote note = (SNote)event.getData();</span><br><span class="line">                view.updateNote(note);</span><br><span class="line">                view.scrollRecyclerViewToTop();</span><br><span class="line">                pushNote(note);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        <span class="keyword">case</span> NotifyEvent.CHANGE_THEME:</span><br><span class="line">            view.reCreate();</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>消息接收的其它操作主要是调用Activity下实现的对笔记的操作方法，此处有几点值得学习:</p>
<ul>
<li><p>首先是RecyclerView的滚动，通过下面的方法可以使RecyclerView平滑地滚动到指定位置</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">scrollRecyclerViewToTop</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    recyclerView.smoothScrollToPosition(<span class="number">0</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p>重建Activity</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">reCreate</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">super</span>.recreate();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ul>
<p>关于消息的发送就放到消息发送消息代码处进行分析。</p>
<h2 id="3-4_onResume_28_29"><a href="#3-4_onResume_28_29" class="headerlink" title="3.4 onResume()"></a>3.4 onResume()</h2><p>onResume比较简单，主要是对已加载配置文件并应用设置，这也告诉我们，通常加载配置文件放在依赖注入处，也就是onCreate中，而应用设置放在onResume中。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onResume</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (isRightHandMode != mPreferenceUtils.getBooleanParam(mContext</span><br><span class="line">            .getString(R.string.right_hand_mode_key)))&#123;</span><br><span class="line">        isRightHandMode = !isRightHandMode;</span><br><span class="line">        <span class="keyword">if</span> (isRightHandMode)&#123;</span><br><span class="line">            view.setMenuGravity(Gravity.END);</span><br><span class="line">        &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">            view.setMenuGravity(Gravity.START);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (isCardItemLayout != mPreferenceUtils.getBooleanParam(mContext</span><br><span class="line">            .getString(R.string.card_note_item_layout_key), <span class="keyword">true</span>))&#123;</span><br><span class="line">        switchItemLayoutManager(!isCardItemLayout);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<blockquote>
<p>switchItemLayoutManager方法最终通过recyclerView.setLayoutManager(manager)设置显示方式。</p>
</blockquote>
<h2 id="3-5__u8FD4_u56DE_u76D1_u542C"><a href="#3-5__u8FD4_u56DE_u76D1_u542C" class="headerlink" title="3.5 返回监听"></a>3.5 返回监听</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">onKeyDown</span><span class="params">(<span class="keyword">int</span> keyCode)</span></span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (keyCode == KeyEvent.KEYCODE_BACK)&#123;</span><br><span class="line">        <span class="keyword">if</span> (view.isDrawerOpen())&#123;</span><br><span class="line">            view.closeDrawer();</span><br><span class="line">        &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">            view.moveTaskToBack();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>这段代码的逻辑是，如果按的不是返回键，则返回false交给系统处理，如果按的是返回键且抽屉未关，则关闭抽屉，否则调用 <code>super.moveTaskToBack(true)</code> 手动隐藏Activity，保持栈结构，将任务移到后台，不会调用onDestroy方法。</p>
<h2 id="3-6__u540C_u6B65_u7B14_u8BB0"><a href="#3-6__u540C_u6B65_u7B14_u8BB0" class="headerlink" title="3.6 同步笔记"></a>3.6 同步笔记</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">sync</span><span class="params">(EverNoteUtils.SyncType type, <span class="keyword">boolean</span> silence)</span></span>&#123;</span><br><span class="line">    <span class="comment">//mEverNoteUtils.sync();</span></span><br><span class="line">    mObservableUtils.sync(mEverNoteUtils, type)</span><br><span class="line">            .subscribeOn(Schedulers.newThread())</span><br><span class="line">            .observeOn(AndroidSchedulers.mainThread())</span><br><span class="line">            .subscribe((result -&gt; &#123;</span><br><span class="line">                <span class="keyword">if</span> (!silence)</span><br><span class="line">                    onEventMainThread(result);</span><br><span class="line">            &#125;));</span><br></pre></td></tr></table></figure>
<p>主要进行笔记的同步。</p>
<h2 id="3-6__u542F_u52A8_u5176_u5B83Activity"><a href="#3-6__u542F_u52A8_u5176_u5B83Activity" class="headerlink" title="3.6 启动其它Activity"></a>3.6 启动其它Activity</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">startNoteActivity</span><span class="params">(<span class="keyword">int</span> type, SNote value)</span></span>&#123;</span><br><span class="line">    Intent intent = <span class="keyword">new</span> Intent(mContext, NoteActivity.class);</span><br><span class="line">    Bundle bundle = <span class="keyword">new</span> Bundle();</span><br><span class="line">    bundle.putInt(NotePresenter.OPERATE_NOTE_TYPE_KEY, type);</span><br><span class="line">    EventBus.getDefault().postSticky(value);</span><br><span class="line">    intent.putExtras(bundle);</span><br><span class="line">    mContext.startActivity(intent);</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">startSettingActivity</span><span class="params">()</span></span>&#123;</span><br><span class="line">    Intent intent = <span class="keyword">new</span> Intent(mContext, SettingActivity.class);</span><br><span class="line">    mContext.startActivity(intent);</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">startAboutActivity</span><span class="params">()</span></span>&#123;</span><br><span class="line">    Intent intent = <span class="keyword">new</span> Intent(mContext, AboutActivity.class);</span><br><span class="line">    mContext.startActivity(intent);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>在MainPresenter的最后，可以找到其它Activity的入口，在下文中，我们将对这些Activity进行分析。<br>先分析Activity还是先看看这两段代码，首先是EventBus的postSticky(value)方法，该方法用于会多次传递的参数，可以通过getStickyEvent(ClasseventType)来获取最新发布的对象。还有传递的Bundle数据，笔者猜测是将”新建”或”编辑”操作参数传递过去。</p>
<h1 id="4-__u7B14_u8BB0_u7F16_u8F91_u754C_u9762"><a href="#4-__u7B14_u8BB0_u7F16_u8F91_u754C_u9762" class="headerlink" title="4. 笔记编辑界面"></a>4. 笔记编辑界面</h1><h2 id="4-1__u754C_u9762_u521D_u59CB_u5316"><a href="#4-1__u754C_u9762_u521D_u59CB_u5316" class="headerlink" title="4.1 界面初始化"></a>4.1 界面初始化</h2><p>首先是界面的初始化操作，也就是onCreate()方法，笔者对此处很好奇，因为没有对Bundle数据进行操作，那么是如何区分编辑模式和新建模式呢，答案就是通过Activity下的getIntent()方法可以获取Intent，再通过重写自BaseActivity的parseIntent()方法设定操作方式。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle savedInstanceState)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">super</span>.onCreate(savedInstanceState);</span><br><span class="line">    initializePresenter();</span><br><span class="line">    notePresenter.onCreate(savedInstanceState);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>其中两个增加的函数分别进行了Presenter的初始化和EventBus的注册。当然此处的super.onCreate(savedInstanceState)调用了父类BaseActivity的onCreate方法。</p>
<h2 id="4-2__u5E03_u5C40_u6587_u4EF6"><a href="#4-2__u5E03_u5C40_u6587_u4EF6" class="headerlink" title="4.2 布局文件"></a>4.2 布局文件</h2><p><img src="http://7xqdz8.com1.z0.glb.clouddn.com/160418sc_new_note.png" alt="新建笔记界面"></p>
<p>布局比较简单，这里仅挑选几个要点:</p>
<ul>
<li>焦点拦截<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">android:focusable=<span class="string">"true"</span></span><br><span class="line">android:focusableInTouchMode=<span class="string">"true"</span></span><br></pre></td></tr></table></figure>
</li>
</ul>
<p>在界面顶部的ListView中捕获焦点，可以焦点拦截使得EditText不会抢先获取焦点。</p>
<ul>
<li><p>ScrollView属性</p>
<ol>
<li><code>android:fadingEdge=&quot;none&quot;</code> : 用于配置边界效果</li>
<li><code>android:cacheColorHint</code> 和 <code>android:scrollingCache</code> : 用于消除缓存机制，使得这种情况下更加流畅</li>
<li><code>android:overScrollMode</code> : 越界模式</li>
</ol>
</li>
<li><p><code>com.rengwuxian.materialedittext.MaterialEditText</code> : 第三方材质风格控件</p>
</li>
<li><code>android:lineSpacingExtra</code> : 行距属性，单位dp</li>
</ul>
<h2 id="4-3__u83DC_u5355_u7BA1_u7406"><a href="#4-3__u83DC_u5355_u7BA1_u7406" class="headerlink" title="4.3 菜单管理"></a>4.3 菜单管理</h2><h3 id="4-3-1__u52A8_u6001_u4FEE_u6539_u83DC_u5355"><a href="#4-3-1__u52A8_u6001_u4FEE_u6539_u83DC_u5355" class="headerlink" title="4.3.1 动态修改菜单"></a>4.3.1 动态修改菜单</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">onPrepareOptionsMenu</span><span class="params">(Menu menu)</span> </span>&#123;</span><br><span class="line">    doneMenuItem = menu.getItem(<span class="number">0</span>);</span><br><span class="line">    notePresenter.onPrepareOptionsMenu();</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">super</span>.onPrepareOptionsMenu(menu);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">onOptionsItemSelected</span><span class="params">(MenuItem item)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (notePresenter.onOptionsItemSelected(item))</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">super</span>.onOptionsItemSelected(item);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>要实现动态修改菜单，关键点在于:<br>onCreateOptionsMenu(Menu menu)方法只在Activity创建时调用一次，而onPrepareOptionsMenu(Menu menu)在每次访问菜单的时候调用。此界面中具体实现逻辑为: 首次通过inflater填充菜单，之后一旦访问菜单即设置为不可见。</p>
<blockquote>
<p>菜单的add()方法是追加式的，需要先调用clear()方法。</p>
</blockquote>
<h2 id="4-4__u521D_u59CB_u5316_u89C6_u56FE"><a href="#4-4__u521D_u59CB_u5316_u89C6_u56FE" class="headerlink" title="4.4 初始化视图"></a>4.4 初始化视图</h2><p>三个方法分别初始化为编辑模式、查看模式、创建模式。其中几点值得注意:</p>
<h3 id="4-4-1__u7126_u70B9_u8BF7_u6C42"><a href="#4-4-1__u7126_u70B9_u8BF7_u6C42" class="headerlink" title="4.4.1 焦点请求"></a>4.4.1 焦点请求</h3><p>对于EditText等View，可以调用labelEditText.requestFocus()捕获焦点。</p>
<h3 id="4-4-2__u76D1_u542C_u5668"><a href="#4-4-2__u76D1_u542C_u5668" class="headerlink" title="4.4.2 监听器"></a>4.4.2 监听器</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">contentEditText.setOnFocusChangeListener(notePresenter);</span><br><span class="line">labelEditText.addTextChangedListener(notePresenter);</span><br></pre></td></tr></table></figure>
<p>此处对文本改变和焦点改变设置了监听，分别用于控制菜单显示和Toolbar标题:</p>
<ul>
<li><p>文本改变</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">String content = contentSrc.replaceAll(<span class="string">"\\s*|\t|\r|\n"</span>, <span class="string">""</span>);</span><br><span class="line"><span class="keyword">if</span> (!TextUtils.isEmpty(content))&#123;</span><br><span class="line">    <span class="keyword">if</span> (TextUtils.equals(labelSrc, note.getLabel()) &amp;&amp; TextUtils.equals(contentSrc, note.getContent()))&#123;</span><br><span class="line">        view.setDoneMenuItemVisible(<span class="keyword">false</span>);</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    view.setDoneMenuItemVisible(<span class="keyword">true</span>);</span><br><span class="line">&#125;<span class="keyword">else</span>&#123;</span><br><span class="line">    view.setDoneMenuItemVisible(<span class="keyword">false</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p>焦点改变</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (hasFocus)&#123;</span><br><span class="line">    view.setToolbarTitle(R.string.edit_note);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h2 id="4-5__u66F4_u591A_u7EC6_u8282"><a href="#4-5__u66F4_u591A_u7EC6_u8282" class="headerlink" title="4.5 更多细节"></a>4.5 更多细节</h2><h3 id="4-5-1__u952E_u76D8_u663E_u793A_u4E0E_u9690_u85CF"><a href="#4-5-1__u952E_u76D8_u663E_u793A_u4E0E_u9690_u85CF" class="headerlink" title="4.5.1 键盘显示与隐藏"></a>4.5.1 键盘显示与隐藏</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">hideKeyBoard</span><span class="params">()</span></span>&#123;</span><br><span class="line">    hideKeyBoard(labelEditText);</span><br><span class="line">&#125;</span><br><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">showKeyBoard</span><span class="params">()</span></span>&#123;</span><br><span class="line">    InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);</span><br><span class="line">    inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, <span class="number">0</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">hideKeyBoard</span><span class="params">(EditText editText)</span></span>&#123;</span><br><span class="line">    InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);</span><br><span class="line">    inputMethodManager.hideSoftInputFromWindow(editText.getWindowToken(), <span class="number">0</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>通过重写方法，再调用InputMethodManager实现了键盘的显示与隐藏。</p>
<h3 id="4-5-2__u63D0_u793A_u7528_u6237_u4FDD_u5B58"><a href="#4-5-2__u63D0_u793A_u7528_u6237_u4FDD_u5B58" class="headerlink" title="4.5.2 提示用户保存"></a>4.5.2 提示用户保存</h3><p>通过显示对话框可以友好地提示用户将笔记保存。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">showNotSaveNoteDialog</span><span class="params">()</span></span>&#123;</span><br><span class="line">    AlertDialog.Builder builder = DialogUtils.makeDialogBuilder(<span class="keyword">this</span>);</span><br><span class="line">    builder.setTitle(R.string.not_save_note_leave_tip);</span><br><span class="line">    builder.setPositiveButton(R.string.sure, notePresenter);</span><br><span class="line">    builder.setNegativeButton(R.string.cancel, notePresenter);</span><br><span class="line">    builder.show();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h2 id="4-6_NotePresenter"><a href="#4-6_NotePresenter" class="headerlink" title="4.6 NotePresenter"></a>4.6 NotePresenter</h2><p>NotePresenter是笔记操作界面与笔记操作逻辑之间的桥梁，一如既往，使用Dagger2点@Inject注解标记构造函数表示此构造函数需要被注入构造所需要的参数，相信到了这里，读者对Dagger有了一定初步的认识。同时要注意的是使用Dagger2依赖注入中，我们不需要对Presenter进行实例化，框架会自动替我们完成这些操作的。</p>
<h3 id="4-6-1__u5B64_u6CE8_u4E00_u63B7"><a href="#4-6-1__u5B64_u6CE8_u4E00_u63B7" class="headerlink" title="4.6.1 孤注一掷"></a>4.6.1 孤注一掷</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onDestroy</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (event != <span class="keyword">null</span>)&#123;</span><br><span class="line">        EventBus.getDefault().post(event);</span><br><span class="line">    &#125;</span><br><span class="line">    EventBus.getDefault().unregister(<span class="keyword">this</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>在Activity销毁时，使用了EventBus将最后的消息发送出去，消息包含新建的笔记的类型(新建类型或修改类型)，以及笔记的具体内容(笔记对象)。这时MainPresenter中的EventBus将会收到消息，并且将收到的消息放到主Activity中进行展示。</p>
<h3 id="4-6-2__u4FDD_u5B58_u7B14_u8BB0"><a href="#4-6-2__u4FDD_u5B58_u7B14_u8BB0" class="headerlink" title="4.6.2 保存笔记"></a>4.6.2 保存笔记</h3><p>刚刚说到将最后的消息发出去，那么最后的消息是怎么得来的呢？这就回到保存笔记方法的逻辑实现了:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">saveNote</span><span class="params">()</span></span>&#123;</span><br><span class="line">    view.hideKeyBoard();</span><br><span class="line">    <span class="keyword">if</span> (TextUtils.isEmpty(view.getLabelText()))&#123;</span><br><span class="line">        note.setLabel(mContext.getString(R.string.default_label));</span><br><span class="line">    &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">        note.setLabel(view.getLabelText());</span><br><span class="line">    &#125;</span><br><span class="line">    note.setContent(view.getContentText());</span><br><span class="line">    note.setLastOprTime(TimeUtils.getCurrentTimeInLong());</span><br><span class="line">    note.setStatus(SNote.Status.NEED_PUSH.getValue());</span><br><span class="line">    event = <span class="keyword">new</span> MainPresenter.NotifyEvent&lt;&gt;();</span><br><span class="line">    <span class="keyword">switch</span> (operateMode)&#123;</span><br><span class="line">        <span class="keyword">case</span> CREATE_NOTE_MODE:</span><br><span class="line">            note.setCreateTime(TimeUtils.getCurrentTimeInLong());</span><br><span class="line">            event.setType(MainPresenter.NotifyEvent.CREATE_NOTE);</span><br><span class="line">            mFinalDb.saveBindId(note);</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        <span class="keyword">default</span>:</span><br><span class="line">            event.setType(MainPresenter.NotifyEvent.UPDATE_NOTE);</span><br><span class="line">            mFinalDb.update(note);</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    event.setData(note);</span><br><span class="line">    view.finishView();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>代码比较简单易懂，没有逐行分析的必要。此处注意的是aFinalDb中的方法 <code>boolean saveBindId(Object entity)</code> 可以直接保存对象到数据库。</p>
<h3 id="4-6-3__u65F6_u95F4_u7684_u683C_u5F0F_u5316"><a href="#4-6-3__u65F6_u95F4_u7684_u683C_u5F0F_u5316" class="headerlink" title="4.6.3 时间的格式化"></a>4.6.3 时间的格式化</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> String <span class="title">getOprTimeLineText</span><span class="params">(SNote note)</span></span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (note == <span class="keyword">null</span> || note.getLastOprTime() == <span class="number">0</span>)</span><br><span class="line">        <span class="keyword">return</span> <span class="string">""</span>;</span><br><span class="line">    String create = mContext.getString(R.string.create);</span><br><span class="line">    String edit = mContext.getString(R.string.last_update);</span><br><span class="line">    StringBuilder sb = <span class="keyword">new</span> StringBuilder();</span><br><span class="line">    <span class="keyword">if</span> (note.getLastOprTime() &lt;= note.getCreateTime() || note.getCreateTime() == <span class="number">0</span>)&#123;</span><br><span class="line">        sb.append(mContext.getString(R.string.note_log_text, create, TimeUtils.getTime(note.getLastOprTime())));</span><br><span class="line">        <span class="keyword">return</span> sb.toString();</span><br><span class="line">    &#125;</span><br><span class="line">    sb.append(mContext.getString(R.string.note_log_text, edit, TimeUtils.getTime(note.getLastOprTime())));</span><br><span class="line">    sb.append(<span class="string">"\n"</span>);</span><br><span class="line">    sb.append(mContext.getString(R.string.note_log_text, create, TimeUtils.getTime(note.getCreateTime())));</span><br><span class="line">    <span class="keyword">return</span> sb.toString();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>这段代码的逻辑就是传入笔记对象，如果没有创建时间(笔者猜想或许因为从备份恢复笔记内容或是其它原因会导致笔记创建的时间消失)就只显示最后一次的修改时间，否则就都进行显示，这里用到了TimeUtils。</p>
<h4 id="4-6-3-1_TimeUtils"><a href="#4-6-3-1_TimeUtils" class="headerlink" title="4.6.3.1 TimeUtils"></a>4.6.3.1 TimeUtils</h4><p>TimeUtils是对时间相关操作的一个封装，其中有一个有意思的方法，就是将时间做一个人性化的格式化，即格式化为”刚刚”、”半小时前”、”3天前”等:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> String <span class="title">getConciseTime</span><span class="params">(<span class="keyword">long</span> timeInMillis, <span class="keyword">long</span> nowInMillis, Context context)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (context == <span class="keyword">null</span>)</span><br><span class="line">        <span class="keyword">return</span> <span class="string">""</span>;</span><br><span class="line">    <span class="keyword">long</span> diff = nowInMillis - timeInMillis;</span><br><span class="line">    <span class="keyword">if</span> (diff &gt;= YEAR_Millis)&#123;</span><br><span class="line">        <span class="keyword">int</span> year = (<span class="keyword">int</span>)(diff / YEAR_Millis);</span><br><span class="line">        <span class="keyword">return</span> context.getString(R.string.before_year, year);</span><br><span class="line">    &#125;</span><br><span class="line">    ...</span><br><span class="line">    <span class="keyword">if</span> (diff &gt;= HALF_HOUR_Millis)&#123;</span><br><span class="line">        <span class="keyword">return</span> context.getString(R.string.before_half_hour);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> context.getString(R.string.just_now);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h3 id="4-6-4__u4FDD_u5B58_u6309_u94AE_u7684_u9690_u73B0"><a href="#4-6-4__u4FDD_u5B58_u6309_u94AE_u7684_u9690_u73B0" class="headerlink" title="4.6.4 保存按钮的隐现"></a>4.6.4 保存按钮的隐现</h3><p>对于保存按钮的自动隐现，实现思路就是判断文本是否改变即可:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onTextChanged</span><span class="params">(CharSequence s, <span class="keyword">int</span> start, <span class="keyword">int</span> before, <span class="keyword">int</span> count)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (view.isDoneMenuItemNull())</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    String labelSrc = view.getLabelText();</span><br><span class="line">    String contentSrc = view.getContentText();</span><br><span class="line">    <span class="comment">//String label = labelSrc.replaceAll("\\s*|\t|\r|\n", "");</span></span><br><span class="line">    String content = contentSrc.replaceAll(<span class="string">"\\s*|\t|\r|\n"</span>, <span class="string">""</span>);</span><br><span class="line">    <span class="keyword">if</span> (!TextUtils.isEmpty(content))&#123;</span><br><span class="line">        <span class="keyword">if</span> (TextUtils.equals(labelSrc, note.getLabel()) &amp;&amp; TextUtils.equals(contentSrc, note.getContent()))&#123;</span><br><span class="line">            view.setDoneMenuItemVisible(<span class="keyword">false</span>);</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        view.setDoneMenuItemVisible(<span class="keyword">true</span>);</span><br><span class="line">    &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">        view.setDoneMenuItemVisible(<span class="keyword">false</span>);</span><br></pre></td></tr></table></figure></p>
<p>不过要注意的是要过滤掉转义字符，此处用的正则表达式进行替换过滤。</p>
<h1 id="5-__u8BBE_u7F6E_u754C_u9762"><a href="#5-__u8BBE_u7F6E_u754C_u9762" class="headerlink" title="5. 设置界面"></a>5. 设置界面</h1><p>转眼就来到了设置界面，还是老套路(这世间多点真诚，少点套路可好)，初始化注射器，不过这次没有立马就发现Presenter在哪里，先不急，继续往下读。</p>
<h2 id="5-1__u521D_u59CB_u5316_u89C6_u56FE"><a href="#5-1__u521D_u59CB_u5316_u89C6_u56FE" class="headerlink" title="5.1 初始化视图"></a>5.1 初始化视图</h2><p>SettingActivity中的代码少的可怜，看来看去唯有SettingFragment值得一析:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">init</span><span class="params">()</span></span>&#123;</span><br><span class="line">    SettingFragment settingFragment = SettingFragment.newInstance();</span><br><span class="line">    getFragmentManager().beginTransaction().replace(R.id.fragment_content, settingFragment).commit();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<blockquote>
<p>注意id <code>fragment_content</code> 是布局文件中仅存的FrameLayout的id。</p>
</blockquote>
<h3 id="5-1-1__u788E_u7247"><a href="#5-1-1__u788E_u7247" class="headerlink" title="5.1.1 碎片"></a>5.1.1 碎片</h3><p>初始化视图方法中，将FrameLayout替换为了SettingFragment，那我们现在就看看SettingFragment到底是怎么一回事。</p>
<h4 id="5-1-1-1__u627F_u63A5_u5173_u7CFB"><a href="#5-1-1-1__u627F_u63A5_u5173_u7CFB" class="headerlink" title="5.1.1.1 承接关系"></a>5.1.1.1 承接关系</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SettingFragment</span> <span class="keyword">extends</span> <span class="title">PreferenceFragment</span> <span class="keyword">implements</span> <span class="title">SettingView</span></span>&#123;</span><br><span class="line">    ...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>SettingFragment继承自SettingView，SettingView中包含有对每个设置项进行设置的方法定义:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">SettingView</span> <span class="keyword">extends</span> <span class="title">View</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">findPreference</span><span class="params">()</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">setRightHandModePreferenceChecked</span><span class="params">(<span class="keyword">boolean</span> checked)</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">setCardLayoutPreferenceChecked</span><span class="params">(<span class="keyword">boolean</span> checked)</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">setFeedbackPreferenceSummary</span><span class="params">(CharSequence c)</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">setFeedbackPreferenceClickListener</span><span class="params">(Preference.OnPreferenceClickListener l)</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">setEverNoteAccountPreferenceSummary</span><span class="params">(CharSequence c)</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">setEverNoteAccountPreferenceTitle</span><span class="params">(CharSequence c)</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">initPreferenceListView</span><span class="params">(android.view.View view)</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">showSnackbar</span><span class="params">(@StringRes <span class="keyword">int</span> message)</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">showThemeChooseDialog</span><span class="params">()</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">boolean</span> <span class="title">isResume</span><span class="params">()</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">showUnbindEverNoteDialog</span><span class="params">()</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">toast</span><span class="params">(@StringRes <span class="keyword">int</span> message)</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">reload</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h4 id="5-1-1-2__u7ED1_u5B9AActivity"><a href="#5-1-1-2__u7ED1_u5B9AActivity" class="headerlink" title="5.1.1.2 绑定Activity"></a>5.1.1.2 绑定Activity</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onAttach</span><span class="params">(Activity activity)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">super</span>.onAttach(activity);</span><br><span class="line">    <span class="keyword">if</span> (getActivity() != <span class="keyword">null</span> &amp;&amp; getActivity() <span class="keyword">instanceof</span> SettingActivity)&#123;</span><br><span class="line">        <span class="keyword">this</span>.activity = (SettingActivity)getActivity();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>在Fragment绑定中，对Fragment中的Activity成员变量进行初始化，防止每次调用getActivity造成性能损失。</p>
<h4 id="5-1-1-3__u8BBE_u7F6E_u9879_u521D_u59CB_u5316"><a href="#5-1-1-3__u8BBE_u7F6E_u9879_u521D_u59CB_u5316" class="headerlink" title="5.1.1.3 设置项初始化"></a>5.1.1.3 设置项初始化</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle savedInstanceState)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">super</span>.onCreate(savedInstanceState);</span><br><span class="line">    initializeDependencyInjector();</span><br><span class="line">    addPreferencesFromResource(R.xml.prefs);</span><br><span class="line">    getPreferenceManager().setSharedPreferencesName(PREFERENCE_FILE_NAME);</span><br><span class="line">    initializePresenter();</span><br><span class="line">    settingPresenter.onCreate(savedInstanceState);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>在onCreate()中，对菜单项进行了初始化，</p>
<h5 id="5-1-1-3-1_PreferenceScreen"><a href="#5-1-1-3-1_PreferenceScreen" class="headerlink" title="5.1.1.3.1 PreferenceScreen"></a>5.1.1.3.1 PreferenceScreen</h5><p>xml文件中使用了 <code>com.jenzz.materialpreference</code> 第三方库，同样是为了让低版本同样拥有Material效果:<br><img src="http://7xqdz8.com1.z0.glb.clouddn.com/160424layout.png" alt="layout预览"><br>此处代码只展示部分:<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="pi">&lt;?xml version="1.0" encoding="utf-8"?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">PreferenceScreen</span> <span class="attribute">xmlns:android</span>=<span class="value">"http://schemas.android.com/apk/res/android"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">com.jenzz.materialpreference.PreferenceCategory</span> <span class="attribute">android:title</span>=<span class="value">"@string/general_settings"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">com.jenzz.materialpreference.CheckBoxPreference</span></span><br><span class="line">        <span class="attribute">android:key</span>=<span class="value">"@string/right_hand_mode_key"</span></span><br><span class="line">        <span class="attribute">android:title</span>=<span class="value">"@string/right_hand_mode"</span></span><br><span class="line">        <span class="attribute">android:summary</span>=<span class="value">"@string/right_hand_mode_summary"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="title">com.jenzz.materialpreference.PreferenceCategory</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">PreferenceScreen</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<h5 id="5-1-1-3-2__u8BBE_u5B9A_u6587_u4EF6"><a href="#5-1-1-3-2__u8BBE_u5B9A_u6587_u4EF6" class="headerlink" title="5.1.1.3.2 设定文件"></a>5.1.1.3.2 设定文件</h5><p>通过PreferenceManager中的setSharedPreferencesName(PREFERENCE_FILE_NAME)方法可以设定配置文件的储存位置。</p>
<h5 id="5-1-1-3-3_Presenter"><a href="#5-1-1-3-3_Presenter" class="headerlink" title="5.1.1.3.3 Presenter"></a>5.1.1.3.3 Presenter</h5><p>此处终于见到了设置界面的Presenter。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">initializePresenter</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    settingPresenter.attachView(<span class="keyword">this</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h5 id="5-1-1-3-4_findPreference"><a href="#5-1-1-3-4_findPreference" class="headerlink" title="5.1.1.3.4 findPreference"></a>5.1.1.3.4 findPreference</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">findPreference</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    rightHandModePreference = (CheckBoxPreference)findPreference(getString(R.string.right_hand_mode_key));</span><br><span class="line">    cardLayoutPreference = (CheckBoxPreference)findPreference(getString(R.string.card_note_item_layout_key));</span><br><span class="line">    feedbackPreference = (Preference)findPreference(getString(R.string.advice_feedback_key));</span><br><span class="line">    everAccountPreference = (Preference)findPreference(getString(R.string.ever_note_account_key));</span><br><span class="line">    payMePreference = (Preference)findPreference(getString(R.string.pay_for_me_key));</span><br><span class="line">    giveFavorPreference = (Preference)findPreference(getString(R.string.give_favor_key));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>与Activity中的findViewById()类似，Preference也类似，需要查找到每个控件，只不过此处通过 <code>key</code> 属性来进行查找。</p>
<h4 id="5-1-1-4__u5BF9_u5916_u63D0_u4F9B_u65B9_u6CD5"><a href="#5-1-1-4__u5BF9_u5916_u63D0_u4F9B_u65B9_u6CD5" class="headerlink" title="5.1.1.4 对外提供方法"></a>5.1.1.4 对外提供方法</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setRightHandModePreferenceChecked</span><span class="params">(<span class="keyword">boolean</span> checked)</span> </span>&#123;</span><br><span class="line">    rightHandModePreference.setChecked(checked);</span><br><span class="line">&#125;</span><br><span class="line">...</span><br></pre></td></tr></table></figure>
<p>之后，对外提供了设置各个设置项的方法。</p>
<h4 id="5-1-1-5_ListView_u81EA_u5B9A_u4E49"><a href="#5-1-1-5_ListView_u81EA_u5B9A_u4E49" class="headerlink" title="5.1.1.5 ListView自定义"></a>5.1.1.5 ListView自定义</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">initPreferenceListView</span><span class="params">(View view)</span> </span>&#123;</span><br><span class="line">    ListView listView = (ListView)view.findViewById(android.R.id.list);</span><br><span class="line">    listView.setHorizontalScrollBarEnabled(<span class="keyword">false</span>);</span><br><span class="line">    listView.setVerticalScrollBarEnabled(<span class="keyword">false</span>);</span><br><span class="line">    listView.setDivider(<span class="keyword">new</span> ColorDrawable(getResources().getColor(R.color.grey)));</span><br><span class="line">    listView.setDividerHeight((<span class="keyword">int</span>) getResources().getDimension(R.dimen.preference_divider_height));</span><br><span class="line">    listView.setFooterDividersEnabled(<span class="keyword">false</span>);</span><br><span class="line">    listView.setHeaderDividersEnabled(<span class="keyword">false</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>之后，通过view.findViewById(android.R.id.list)获取ListView，可以对该ListView进行自定义。如图为笔者加入垂直滚动条后的效果:<br><img src="http://7xqdz8.com1.z0.glb.clouddn.com/160424setting.png" alt="设置界面"></p>
<blockquote>
<p>view为重写SettingFragment下的onViewCreated(View view, Bundle savedInstanceState)方法中的参数。</p>
</blockquote>
<h2 id="5-2__u4E3B_u9898_u5207_u6362_u5BF9_u8BDD_u6846"><a href="#5-2__u4E3B_u9898_u5207_u6362_u5BF9_u8BDD_u6846" class="headerlink" title="5.2 主题切换对话框"></a>5.2 主题切换对话框</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">showThemeChooseDialog</span><span class="params">()</span></span>&#123;</span><br><span class="line">    AlertDialog.Builder builder = DialogUtils.makeDialogBuilder(activity);</span><br><span class="line">    builder.setTitle(R.string.change_theme);</span><br><span class="line">    Integer[] res = <span class="keyword">new</span> Integer[]&#123;R.drawable.red_round, R.drawable.brown_round, R.drawable.blue_round,</span><br><span class="line">            R.drawable.blue_grey_round, R.drawable.yellow_round, R.drawable.deep_purple_round,</span><br><span class="line">            R.drawable.pink_round, R.drawable.green_round&#125;;</span><br><span class="line">    List&lt;Integer&gt; list = Arrays.asList(res);</span><br><span class="line">    ColorsListAdapter adapter = <span class="keyword">new</span> ColorsListAdapter(getActivity(), list);</span><br><span class="line">    adapter.setCheckItem(ThemeUtils.getCurrentTheme(activity).getIntValue());</span><br><span class="line">    GridView gridView = (GridView)LayoutInflater.from(activity).inflate(R.layout.colors_panel_layout, <span class="keyword">null</span>);</span><br><span class="line">    gridView.setStretchMode(GridView.STRETCH_COLUMN_WIDTH);</span><br><span class="line">    gridView.setCacheColorHint(<span class="number">0</span>);</span><br><span class="line">    gridView.setAdapter(adapter);</span><br><span class="line">    builder.setView(gridView);</span><br><span class="line">    <span class="keyword">final</span> AlertDialog dialog = builder.show();</span><br><span class="line">    gridView.setOnItemClickListener((parent, view, position, id) -&gt; &#123;</span><br><span class="line">        dialog.dismiss();</span><br><span class="line">        settingPresenter.onThemeChoose(position);</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="5-2-1__u4E3B_u9898_u989C_u8272_u5B50_u9879"><a href="#5-2-1__u4E3B_u9898_u989C_u8272_u5B50_u9879" class="headerlink" title="5.2.1 主题颜色子项"></a>5.2.1 主题颜色子项</h3><p>我们来仔细分析一下此段代码，首先将每个颜色的资源id存放入了list集合，颜色资源的代码如下，此处只展示红色:<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">shape</span> <span class="attribute">xmlns:android</span>=<span class="value">"http://schemas.android.com/apk/res/android"</span></span><br><span class="line">       <span class="attribute">android:shape</span>=<span class="value">"oval"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">solid</span> <span class="attribute">android:color</span>=<span class="value">"@color/red"</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">shape</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<p>接下来，使用了ColorsListAdapter作为GridView的适配器，之后很巧妙地使用两张图片重合的FrameLayout作为一个子项实现了主题选择的效果:<br><img src="http://7xqdz8.com1.z0.glb.clouddn.com/160424theme.png" alt="主题选择对话框"><br>在打开对话框时，还需要通过读取配置文件来设置当前所应用的主题。</p>
<h3 id="5-2-2__u7F51_u683C_u89C6_u56FE"><a href="#5-2-2__u7F51_u683C_u89C6_u56FE" class="headerlink" title="5.2.2 网格视图"></a>5.2.2 网格视图</h3><p>网格视图使用LayoutInflater来进行了初始化，其布局如下:<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">GridView</span> <span class="attribute">xmlns:android</span>=<span class="value">"http://schemas.android.com/apk/res/android"</span></span><br><span class="line">    <span class="attribute">android:orientation</span>=<span class="value">"vertical"</span> <span class="attribute">android:layout_width</span>=<span class="value">"match_parent"</span></span><br><span class="line">    <span class="attribute">android:numColumns</span>=<span class="value">"4"</span></span><br><span class="line">    <span class="attribute">android:padding</span>=<span class="value">"@dimen/md_dialog_frame_margin"</span></span><br><span class="line">    <span class="attribute">android:background</span>=<span class="value">"@android:color/transparent"</span></span><br><span class="line">    <span class="attribute">android:listSelector</span>=<span class="value">"@android:color/transparent"</span></span><br><span class="line">    <span class="attribute">android:horizontalSpacing</span>=<span class="value">"20dp"</span></span><br><span class="line">    <span class="attribute">android:verticalSpacing</span>=<span class="value">"20dp"</span></span><br><span class="line">    <span class="attribute">android:layout_height</span>=<span class="value">"match_parent"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">GridView</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<blockquote>
<p>要注意设置背景和所选项的颜色为透明</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">gridView.setStretchMode(GridView.STRETCH_COLUMN_WIDTH);</span><br><span class="line">gridView.setCacheColorHint(<span class="number">0</span>);</span><br><span class="line">gridView.setAdapter(adapter);</span><br></pre></td></tr></table></figure>
<p>接下来对gridView设置了伸展模式等。</p>
<h3 id="5-2-3__u70B9_u51FB_u4E8B_u4EF6"><a href="#5-2-3__u70B9_u51FB_u4E8B_u4EF6" class="headerlink" title="5.2.3 点击事件"></a>5.2.3 点击事件</h3><p>最后对其设定点击事件，实现主题切换。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">gridView.setOnItemClickListener((parent, view, position, id) -&gt; &#123;</span><br><span class="line">    dialog.dismiss();</span><br><span class="line">    settingPresenter.onThemeChoose(position);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></p>
<p>其中切换后会调用reload()方法，以实现无动画地重启Activity，之前BaseActivity中已有提及。</p>
<h2 id="5-3_SettingPresenter"><a href="#5-3_SettingPresenter" class="headerlink" title="5.3 SettingPresenter"></a>5.3 SettingPresenter</h2><h3 id="5-3-1_onCreate_28_29"><a href="#5-3-1_onCreate_28_29" class="headerlink" title="5.3.1 onCreate()"></a>5.3.1 onCreate()</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle savedInstanceState)</span> </span>&#123;</span><br><span class="line">    EventBus.getDefault().register(<span class="keyword">this</span>);</span><br><span class="line">    view.findPreference();</span><br><span class="line">    initOtherPreference();</span><br><span class="line">    initFeedbackPreference();</span><br><span class="line">    initEverAccountPreference();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>onCreate()中调用了之前提及的findPreference操作，并对设置项进行了初始化，此处展示部分初始化:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">initOtherPreference</span><span class="params">()</span></span>&#123;</span><br><span class="line">    isCardLayout = mPreferenceUtils.getBooleanParam(getString(mContext,</span><br><span class="line">            R.string.card_note_item_layout_key), <span class="keyword">true</span>);</span><br><span class="line">    isRightHandMode = mPreferenceUtils.getBooleanParam(getString(mContext,</span><br><span class="line">            R.string.right_hand_mode_key));</span><br><span class="line">    view.setCardLayoutPreferenceChecked(isCardLayout);</span><br><span class="line">    view.setRightHandModePreferenceChecked(isRightHandMode);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h3 id="5-3-2__u90AE_u4EF6_u53D1_u9001"><a href="#5-3-2__u90AE_u4EF6_u53D1_u9001" class="headerlink" title="5.3.2 邮件发送"></a>5.3.2 邮件发送</h3><p>关于意见反馈功能，此应用只是简单使用了发送邮件作为反馈方式，代码不难:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">initFeedbackPreference</span><span class="params">()</span></span>&#123;</span><br><span class="line">    Uri uri = Uri.parse(<span class="string">"mailto:lgpszu@163.com"</span>);</span><br><span class="line">    <span class="keyword">final</span> Intent intent = <span class="keyword">new</span> Intent(Intent.ACTION_SENDTO, uri);</span><br><span class="line">    PackageManager pm = mContext.getPackageManager();</span><br><span class="line">    List&lt;ResolveInfo&gt; infos = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);</span><br><span class="line">    <span class="keyword">if</span> (infos == <span class="keyword">null</span> || infos.size() &lt;= <span class="number">0</span>)&#123;</span><br><span class="line">        view.setFeedbackPreferenceSummary(mContext.getString(R.string.no_email_app_tip));</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    Preference.OnPreferenceClickListener l = (preference -&gt; &#123;</span><br><span class="line">        mContext.startActivity(intent);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125;);</span><br><span class="line">    view.setFeedbackPreferenceClickListener(l);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>值得学习的是通过PackageManager查询符合要求的Intent应用。</p>
<h3 id="5-3-3__u5907_u4EFD_u7B14_u8BB0"><a href="#5-3-3__u5907_u4EFD_u7B14_u8BB0" class="headerlink" title="5.3.3 备份笔记"></a>5.3.3 备份笔记</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">backupLocal</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="comment">//已经备份中，直接返回</span></span><br><span class="line">    <span class="keyword">if</span> (backuping)</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    backuping = <span class="keyword">true</span>;</span><br><span class="line">    PermissionRequester.getInstance(mContext).</span><br><span class="line">            request(<span class="keyword">new</span> PermissionRequester.RequestPermissionsResultCallBackImpl() &#123;</span><br><span class="line">                <span class="annotation">@Override</span></span><br><span class="line">                <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onRequestPermissionsResult</span><span class="params">(String[] permission, <span class="keyword">int</span>[] grantResult)</span> </span>&#123;</span><br><span class="line">                    <span class="keyword">if</span> (grantResult[<span class="number">0</span>] != PackageManager.PERMISSION_GRANTED) &#123;</span><br><span class="line">                        view.showSnackbar(R.string.backup_local_fail);</span><br><span class="line">                        <span class="keyword">return</span>;</span><br><span class="line">                    &#125;</span><br><span class="line">                    mObservableUtils.backNotes(mContext, mFinalDb, mFileUtils)</span><br><span class="line">                            .subscribeOn(Schedulers.io())</span><br><span class="line">                            .observeOn(AndroidSchedulers.mainThread())</span><br><span class="line">                            .subscribe((success) -&gt; &#123;</span><br><span class="line">                                view.showSnackbar(R.string.backup_local_done);</span><br><span class="line">                                backuping = <span class="keyword">false</span>;</span><br><span class="line">                            &#125;, (e) -&gt; &#123;</span><br><span class="line">                                view.showSnackbar(R.string.backup_local_fail);</span><br><span class="line">                                backuping = <span class="keyword">false</span>;</span><br><span class="line">                            &#125;);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;, Manifest.permission.WRITE_EXTERNAL_STORAGE);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>首先作者使用到了自己封装的一个权限申请类，用于Android 6.0的动态申请权限，在申请成功后再通过RxJava备份笔记。<br>请求权限的核心代码为:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">handleIntent</span><span class="params">(Intent intent)</span> </span>&#123;</span><br><span class="line">    String[] permissions = intent.getStringArrayExtra(<span class="string">"permissions"</span>);</span><br><span class="line">    ActivityCompat.requestPermissions(<span class="keyword">this</span>, permissions, <span class="number">0x44</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onRequestPermissionsResult</span><span class="params">(<span class="keyword">int</span> requestCode, String[] permissions, <span class="keyword">int</span>[] grantResults)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (requestCode == <span class="number">0x44</span>)&#123;</span><br><span class="line">        PermissionRequester.getInstance(<span class="keyword">this</span>).onRequestPermissionsResult(permissions, grantResults);</span><br><span class="line">    &#125;</span><br><span class="line">    finish();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h3 id="5-3-4__u5E94_u7528_u8BC4_u5206"><a href="#5-3-4__u5E94_u7528_u8BC4_u5206" class="headerlink" title="5.3.4 应用评分"></a>5.3.4 应用评分</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">giveFavor</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        Uri uri = Uri.parse(<span class="string">"market://details?id="</span> + mContext.getPackageName());</span><br><span class="line">        Intent intent = <span class="keyword">new</span> Intent(Intent.ACTION_VIEW, uri);</span><br><span class="line">        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);</span><br><span class="line">        mContext.startActivity(intent);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (ActivityNotFoundException e) &#123;</span><br><span class="line">        e.printStackTrace();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>通过以上代码可以打开应用商店搜索此应用，便于用户对此应用评分。</p>
<h3 id="5-3-5__u6253_u8D4F_u6A21_u5757"><a href="#5-3-5__u6253_u8D4F_u6A21_u5757" class="headerlink" title="5.3.5 打赏模块"></a>5.3.5 打赏模块</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (TextUtils.equals(key, getString(mContext, R.string.pay_for_me_key)))&#123;</span><br><span class="line">    Intent intent = <span class="keyword">new</span> Intent(mContext, PayActivity.class);</span><br><span class="line">    mContext.startActivity(intent);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>在onPreferenceTreeClick(Preference preference)方法中进行了操作判断，此处还有一项是PayActivity，即支付。<br>比较简单，就是放一个支付宝二维码图片和文本框，不过这里要说的它的文本框文字是居中的，是因为使用了 <code>android:textAppearance=&quot;?android:attr/textAppearanceMedium&quot;</code> 属性。</p>
<h1 id="6-_AboutActivity"><a href="#6-_AboutActivity" class="headerlink" title="6. AboutActivity"></a>6. AboutActivity</h1><p><img src="http://7xqdz8.com1.z0.glb.clouddn.com/160424about.png" alt="关于"><br>如图展示的就是关于界面，关于界面终于没有使用Presenter了，所以代码看起来也不那么绕了，不过要承认的是代码的逻辑性确实不如之前那么强了。</p>
<h2 id="6-1__u521D_u59CB_u5316_u89C6_u56FE"><a href="#6-1__u521D_u59CB_u5316_u89C6_u56FE" class="headerlink" title="6.1 初始化视图"></a>6.1 初始化视图</h2><p>视图初始化其实没什么说的，先看布局文件。</p>
<h3 id="6-1-1__u5E03_u5C40_u6587_u4EF6"><a href="#6-1-1__u5E03_u5C40_u6587_u4EF6" class="headerlink" title="6.1.1 布局文件"></a>6.1.1 布局文件</h3><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">ScrollView</span></span><br><span class="line">    <span class="attribute">xmlns:android</span>=<span class="value">"http://schemas.android.com/apk/res/android"</span></span><br><span class="line">    <span class="attribute">android:id</span>=<span class="value">"@+id/scroll_view"</span></span><br><span class="line">    <span class="attribute">android:layout_width</span>=<span class="value">"match_parent"</span></span><br><span class="line">    <span class="attribute">android:layout_height</span>=<span class="value">"match_parent"</span></span><br><span class="line">    <span class="attribute">android:fadingEdge</span>=<span class="value">"none"</span></span><br><span class="line">    <span class="attribute">android:scrollbars</span>=<span class="value">"none"</span></span><br><span class="line">    <span class="attribute">android:cacheColorHint</span>=<span class="value">"@android:color/transparent"</span></span><br><span class="line">    <span class="attribute">android:scrollingCache</span>=<span class="value">"false"</span></span><br><span class="line">    <span class="attribute">android:overScrollMode</span>=<span class="value">"never"</span>&gt;</span></span><br><span class="line">...</span><br><span class="line"><span class="tag">&lt;/<span class="title">ScrollView</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>线性布局下就是一个ScrollView，可以兼容小屏幕手机，同时还能默认隐藏版权说明。还有就是涟漪按钮的实现，其实是使用第三方容器包裹住Button即可:<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">com.balysv.materialripple.MaterialRippleLayout</span></span><br><span class="line">    <span class="attribute">android:layout_marginTop</span>=<span class="value">"120dp"</span></span><br><span class="line">    <span class="attribute">android:layout_marginLeft</span>=<span class="value">"30dp"</span></span><br><span class="line">    <span class="attribute">android:layout_marginRight</span>=<span class="value">"30dp"</span></span><br><span class="line">    <span class="attribute">android:layout_width</span>=<span class="value">"match_parent"</span></span><br><span class="line">    <span class="attribute">android:layout_height</span>=<span class="value">"wrap_content"</span></span><br><span class="line">    <span class="attribute">xmlns:app</span>=<span class="value">"http://schemas.android.com/apk/res-auto"</span></span><br><span class="line">    <span class="attribute">app:mrl_rippleOverlay</span>=<span class="value">"true"</span></span><br><span class="line">    <span class="attribute">app:mrl_rippleColor</span>=<span class="value">"?attr/colorPrimary"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">Button</span></span><br><span class="line">        <span class="attribute">android:background</span>=<span class="value">"@drawable/white_button_background"</span></span><br><span class="line">        <span class="attribute">android:id</span>=<span class="value">"@+id/blog_btn"</span></span><br><span class="line">        <span class="attribute">android:textColor</span>=<span class="value">"?attr/colorPrimary"</span></span><br><span class="line">        <span class="attribute">android:text</span>=<span class="value">"@string/jianshu_blog"</span></span><br><span class="line">        <span class="attribute">android:textSize</span>=<span class="value">"@dimen/abc_text_size_button_material"</span></span><br><span class="line">        <span class="attribute">android:layout_width</span>=<span class="value">"match_parent"</span></span><br><span class="line">        <span class="attribute">android:layout_height</span>=<span class="value">"wrap_content"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">com.balysv.materialripple.MaterialRippleLayout</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<h3 id="6-1-2__u7248_u672C_u4FE1_u606F"><a href="#6-1-2__u7248_u672C_u4FE1_u606F" class="headerlink" title="6.1.2 版本信息"></a>6.1.2 版本信息</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> String <span class="title">getVersion</span><span class="params">(Context ctx)</span></span>&#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        PackageManager pm = ctx.getPackageManager();</span><br><span class="line">        PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES);</span><br><span class="line">        <span class="keyword">return</span> pi.versionName;</span><br><span class="line">    &#125;<span class="keyword">catch</span> (PackageManager.NameNotFoundException e)&#123;</span><br><span class="line">        e.printStackTrace();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">"1.0.0"</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>通过以上代码便可获得版本信息。</p>
<h3 id="6-1-3__u8FDE_u7EED_u6572_u51FB_u5F69_u86CB"><a href="#6-1-3__u8FDE_u7EED_u6572_u51FB_u5F69_u86CB" class="headerlink" title="6.1.3 连续敲击彩蛋"></a>6.1.3 连续敲击彩蛋</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@OnClick</span>(R.id.version_text)</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">versionClick</span><span class="params">(View view)</span></span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (clickCount &lt; <span class="number">3</span>)&#123;</span><br><span class="line">        <span class="keyword">if</span> (TimeUtils.getCurrentTimeInLong() - lastClickTime &lt; <span class="number">500</span> || lastClickTime &lt;= <span class="number">0</span>)&#123;</span><br><span class="line">            clickCount ++;</span><br><span class="line">            <span class="keyword">if</span> (clickCount &gt;= <span class="number">3</span>)&#123;</span><br><span class="line">                startViewAction(BuildConfig.ABOUT_APP_URL);</span><br><span class="line">                clickCount = <span class="number">0</span>;</span><br><span class="line">                lastClickTime = <span class="number">0</span>;</span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">            clickCount = <span class="number">0</span>;</span><br><span class="line">            lastClickTime = <span class="number">0</span>;</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        lastClickTime = TimeUtils.getCurrentTimeInLong();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>通过连续地快速点击三次，可以执行彩蛋，就是跳转至作者的博客。</p>
<h2 id="6-2__u5206_u4EAB_u5BF9_u8BDD_u6846"><a href="#6-2__u5206_u4EAB_u5BF9_u8BDD_u6846" class="headerlink" title="6.2 分享对话框"></a>6.2 分享对话框</h2><p>在笔者看来，关于界面真正的大头是这个分享对话框，如图所示。<br><img src="http://7xqdz8.com1.z0.glb.clouddn.com/160424share.png" alt="分享"><br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">showShareDialog</span><span class="params">()</span></span>&#123;</span><br><span class="line">    AlertDialog.Builder builder = <span class="keyword">new</span> AlertDialog.Builder(<span class="keyword">this</span>, R.style.ShareDialog);</span><br><span class="line">    builder.setTitle(getString(R.string.share));</span><br><span class="line">    <span class="keyword">final</span> MaterialSimpleListAdapter adapter = <span class="keyword">new</span> MaterialSimpleListAdapter(<span class="keyword">this</span>);</span><br><span class="line">    String[] array = getResources().getStringArray(R.array.share_dialog_text);</span><br><span class="line">    adapter.add(<span class="keyword">new</span> ShareListItem.Builder(<span class="keyword">this</span>)</span><br><span class="line">            .content(array[<span class="number">0</span>])</span><br><span class="line">            .icon(R.drawable.ic_wx_logo)</span><br><span class="line">            .build());</span><br><span class="line">    ...</span><br><span class="line">    builder.setAdapter(adapter, (dialog, which) -&gt; &#123;</span><br><span class="line">        <span class="keyword">switch</span> (which) &#123;</span><br><span class="line">            <span class="keyword">case</span> <span class="number">0</span>:</span><br><span class="line">                shareToWeChatSession();</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            ...</span><br><span class="line">            <span class="keyword">default</span>:</span><br><span class="line">                share(<span class="string">""</span>, <span class="keyword">null</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br><span class="line">    AlertDialog dialog = builder.create();</span><br><span class="line">    Window window = dialog.getWindow();</span><br><span class="line">    window.setGravity(Gravity.BOTTOM);</span><br><span class="line">    WindowManager.LayoutParams lp = window.getAttributes();</span><br><span class="line">    Display display = getWindowManager().getDefaultDisplay();</span><br><span class="line">    Point out = <span class="keyword">new</span> Point();</span><br><span class="line">    display.getSize(out);</span><br><span class="line">    lp.width = out.x;</span><br><span class="line">    window.setAttributes(lp);</span><br><span class="line">    View decorView = window.getDecorView();</span><br><span class="line">    decorView.setBackgroundColor(getResources().getColor(R.color.window_background));</span><br><span class="line">    dialog.setOnShowListener((dialog1 -&gt; &#123;</span><br><span class="line">        Animator animator = ObjectAnimator</span><br><span class="line">                .ofFloat(decorView, <span class="string">"translationY"</span>, decorView.getMeasuredHeight() / <span class="number">1.5F</span>, <span class="number">0</span>);</span><br><span class="line">        animator.setDuration(<span class="number">200</span>);</span><br><span class="line">        animator.start();</span><br><span class="line">    &#125;));</span><br><span class="line">    dialog.show();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>值得一提的还有对话框的样式:<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">style</span> <span class="attribute">name</span>=<span class="value">"ShareDialog"</span> <span class="attribute">parent</span>=<span class="value">"BaseDialogTheme"</span>&gt;</span><span class="css"></span><br><span class="line">    &lt;<span class="tag">item</span> <span class="tag">name</span>="<span class="tag">android</span><span class="pseudo">:windowFrame"</span>&gt;<span class="at_rule">@<span class="keyword">null&lt;/item&gt;</span></span><br><span class="line">    &lt;item name=<span class="string">"android:windowNoTitle"</span>&gt;true&lt;/item&gt;</span><br><span class="line">    &lt;item name=<span class="string">"android:windowBackground"</span>&gt;@android:color/transparent&lt;/item&gt;</span><br><span class="line">    &lt;item name=<span class="string">"android:windowIsFloating"</span>&gt;true&lt;/item&gt;</span><br><span class="line"></span></span><span class="tag">&lt;/<span class="title">style</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<p>但由于分享并不是主要功能，所以这里就不作分析了，感兴趣的读者可以自行深入研究。</p>
<h1 id="u603B_u7ED3"><a href="#u603B_u7ED3" class="headerlink" title="总结"></a>总结</h1><p>到这里，没有煽情的结尾，《极简笔记》应用的源码就基本分析完了，从中看到了作者对MVP、RxJava、依赖注入等运用的淋漓尽致，这里真心感谢作者 <code>lguipeng</code> 提供的此开源项目供我们学习，也感谢读者你的来访和阅读，希望读者也能或多或少从中学到一些东西！最后欢迎读者访问我的其它博客，也都同样精彩！</p>
<hr>
<h1 id="u53C2_u8003"><a href="#u53C2_u8003" class="headerlink" title="参考"></a>参考</h1><ol>
<li>项目原地址 <a href="https://github.com/lguipeng/Notes" target="_blank" rel="external">lguipeng/Notes</a></li>
<li><a href="http://codethink.me/2015/08/06/dependency-injection-with-dagger-2/" target="_blank" rel="external">使用Dagger 2进行依赖注入</a></li>
<li><a href="http://www.cnblogs.com/yangecnu/p/Introduce-Dependency-Injection.html" target="_blank" rel="external">浅谈依赖注入</a></li>
<li><a href="http://blog.csdn.net/fyh2003/article/details/6913207" target="_blank" rel="external">textAppearance解析</a></li>
<li><a href="http://www.cnblogs.com/yejiurui/p/4962286.html" target="_blank" rel="external">android中xmlns:tools属性详解</a></li>
<li><a href="http://josh-persistence.iteye.com/blog/2226493" target="_blank" rel="external">深入浅出Java Annotation(元注解和自定义注解）</a></li>
<li><a href="http://my.oschina.net/yangfuhai/blog/87459" target="_blank" rel="external">使用android快速开发框架afinal的FinalDb操作android数据库</a></li>
<li><a href="http://gank.io/post/560e15be2dca930e00da1083" target="_blank" rel="external">给 Android 开发者的 RxJava 详解</a></li>
<li><a href="http://blog.csdn.net/harvic880925/article/details/40660137" target="_blank" rel="external">EventBus使用详解</a></li>
</ol>

      
    </div>
    
    
    

    

    
      <div>
        <div style="padding: 10px 0; margin: 20px auto; width: 90%; text-align: center;">
  <div></div>
  <button id="rewardButton" disable="enable" onclick="var qr = document.getElementById('QR'); if (qr.style.display === 'none') {qr.style.display='block';} else {qr.style.display='none'}">
    <span>打赏</span>
  </button>
  <div id="QR" style="display: none;">

    
      <div id="wechat" style="display: inline-block">
        <img id="wechat_qr" src="http://7xqdz8.com1.z0.glb.clouddn.com/pay_weixin.png" alt="Voyager 微信支付"/>
        <p>微信支付</p>
      </div>
    

    
      <div id="alipay" style="display: inline-block">
        <img id="alipay_qr" src="http://7xqdz8.com1.z0.glb.clouddn.com/pay_alipay.jpg" alt="Voyager 支付宝"/>
        <p>支付宝</p>
      </div>
    

    

  </div>
</div>

      </div>
    

    

    <footer class="post-footer">
      
        <div class="post-tags">
          
            <a href="/tags/Android/" rel="tag"># Android</a>
          
            <a href="/tags/源码分析/" rel="tag"># 源码分析</a>
          
        </div>
      

      
      
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/2016/03/19/RxJavaIntroduce/" rel="next" title="RxJava入门学习笔记">
                <i class="fa fa-chevron-left"></i> RxJava入门学习笔记
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/2016/04/22/160422fileuploadbug/" rel="prev" title="JSP+Servlet使用commons-fileupload上传文件连接被重置解决方案">
                JSP+Servlet使用commons-fileupload上传文件连接被重置解决方案 <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </div>
  
  
  
  </article>



    <div class="post-spread">
      
    </div>
  </div>


          </div>
          


          
  


        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap">
            文章目录
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview-wrap">
            站点概览
          </li>
        </ul>
      

      <section class="site-overview-wrap sidebar-panel">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
            
              <img class="site-author-image" itemprop="image"
                src="http://7xqdz8.com1.z0.glb.clouddn.com/avatar.png"
                alt="Voyager" />
            
              <p class="site-author-name" itemprop="name">Voyager</p>
              <p class="site-description motion-element" itemprop="description">Android Developer</p>
          </div>

          <nav class="site-state motion-element">

            
              <div class="site-state-item site-state-posts">
              
                <a href="/archives/">
              
                  <span class="site-state-item-count">41</span>
                  <span class="site-state-item-name">日志</span>
                </a>
              </div>
            

            
              
              
              <div class="site-state-item site-state-categories">
                <a href="/categories/index.html">
                  <span class="site-state-item-count">8</span>
                  <span class="site-state-item-name">分类</span>
                </a>
              </div>
            

            
              
              
              <div class="site-state-item site-state-tags">
                
                  <span class="site-state-item-count">10</span>
                  <span class="site-state-item-name">标签</span>
                
              </div>
            

          </nav>

          

          <div class="links-of-author motion-element">
            
              
                <span class="links-of-author-item">
                  <a href="https://github.com/a-voyager" target="_blank" title="GitHub">
                    
                      <i class="fa fa-fw fa-github"></i>GitHub</a>
                </span>
              
                <span class="links-of-author-item">
                  <a href="mailto:w19961009@126.com" target="_blank" title="E-Mail">
                    
                      <i class="fa fa-fw fa-envelope"></i>E-Mail</a>
                </span>
              
                <span class="links-of-author-item">
                  <a href="https://weibo.com/u/2306071720" target="_blank" title="微博">
                    
                      <i class="fa fa-fw fa-weibo"></i>微博</a>
                </span>
              
            
          </div>

          
          

          
          

          

        </div>
      </section>

      
      <!--noindex-->
        <section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
          <div class="post-toc">

            
              
            

            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#0-__u4ECB_u7ECD"><span class="nav-number">1.</span> <span class="nav-text">0. 介绍</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#1-_Manifest_u5165_u624B"><span class="nav-number">2.</span> <span class="nav-text">1. Manifest入手</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-1__u6743_u9650"><span class="nav-number">2.1.</span> <span class="nav-text">1.1 权限</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#1-2_Application_u5C42"><span class="nav-number">2.2.</span> <span class="nav-text">1.2 Application层</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-2-1__u63A2_u7D22_u7EE7_u627F_u81EAApplication_u7684App_u7C7B"><span class="nav-number">2.2.1.</span> <span class="nav-text">1.2.1 探索继承自Application的App类</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-2-1-1_Dagger2_u4ECB_u7ECD"><span class="nav-number">2.2.2.</span> <span class="nav-text">1.2.1.1 Dagger2介绍</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-2-1-1_Dagger2_u7684_u4F7F_u7528"><span class="nav-number">2.2.3.</span> <span class="nav-text">1.2.1.1 Dagger2的使用</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#1-3_Activity_u5C42"><span class="nav-number">2.3.</span> <span class="nav-text">1.3 Activity层</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#1-3-1__u641C_u7D22_u529F_u80FD_u7684_u4F7F_u7528_u65B9_u6CD5"><span class="nav-number">2.4.</span> <span class="nav-text">1.3.1 搜索功能的使用方法</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-3-1-1__u521B_u5EFA_u641C_u7D22_u914D_u7F6E_u6587_u4EF6"><span class="nav-number">2.4.1.</span> <span class="nav-text">1.3.1.1 创建搜索配置文件</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-3-1-2__u521B_u5EFAActivity_u5E76_u6CE8_u518C"><span class="nav-number">2.4.2.</span> <span class="nav-text">1.3.1.2 创建Activity并注册</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-3-1-3__u6267_u884C_u641C_u7D22_u8FC7_u7A0B"><span class="nav-number">2.4.3.</span> <span class="nav-text">1.3.1.3 执行搜索过程</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-3-1-4__u8FDB_u884C_u5B9E_u65F6_u641C_u7D22"><span class="nav-number">2.4.4.</span> <span class="nav-text">1.3.1.4 进行实时搜索</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#2-__u653B_u5165MainActivity"><span class="nav-number">3.</span> <span class="nav-text">2. 攻入MainActivity</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#2-1_ButterKnife"><span class="nav-number">3.1.</span> <span class="nav-text">2.1 ButterKnife</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#2-1-1__u4F7F_u7528_u65B9_u6CD5"><span class="nav-number">3.1.1.</span> <span class="nav-text">2.1.1 使用方法</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-2__u57FA_u7C7B_u548C_u63A5_u53E3"><span class="nav-number">3.2.</span> <span class="nav-text">2.2 基类和接口</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#2-2-1__u91CD_u5199Activity_u751F_u547D_u5468_u671F_u7684BaseActivity"><span class="nav-number">3.2.1.</span> <span class="nav-text">2.2.1 重写Activity生命周期的BaseActivity</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#2-2-1-1__u5904_u7406_u6570_u636E"><span class="nav-number">3.2.1.1.</span> <span class="nav-text">2.2.1.1 处理数据</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-2-1-2__u8FC7_u6E21_u52A8_u753B"><span class="nav-number">3.2.1.2.</span> <span class="nav-text">2.2.1.2 过渡动画</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-2-1-3__u4E3B_u9898_u5207_u6362"><span class="nav-number">3.2.1.3.</span> <span class="nav-text">2.2.1.3 主题切换</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-2-1-4__u9488_u5BF9KitKat_u7684_u72B6_u6001_u680F_u201D_u6C89_u6D78_u6A21_u5F0F_u201D"><span class="nav-number">3.2.1.4.</span> <span class="nav-text">2.2.1.4 针对KitKat的状态栏”沉浸模式”</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-2-1-5__u89C6_u56FE_u521D_u59CB_u5316"><span class="nav-number">3.2.1.5.</span> <span class="nav-text">2.2.1.5 视图初始化</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-2-1-6_Toolbar_u521D_u59CB_u5316"><span class="nav-number">3.2.1.6.</span> <span class="nav-text">2.2.1.6 Toolbar初始化</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-2-1-7__u91CD_u542FActivity"><span class="nav-number">3.2.1.7.</span> <span class="nav-text">2.2.1.7 重启Activity</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-2-2_MainView_u63A5_u53E3"><span class="nav-number">3.2.2.</span> <span class="nav-text">2.2.2 MainView接口</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-3_MainPresenter_u6865_u6881"><span class="nav-number">3.3.</span> <span class="nav-text">2.3 MainPresenter桥梁</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-4_onCreate_28_29_u7684_u91CD_u5199"><span class="nav-number">3.4.</span> <span class="nav-text">2.4 onCreate()的重写</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-5__u4E3B_u5E03_u5C40_u6587_u4EF6_u5206_u6790"><span class="nav-number">3.5.</span> <span class="nav-text">2.5 主布局文件分析</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#2-5-1__u5934_u58F0_u660E"><span class="nav-number">3.5.1.</span> <span class="nav-text">2.5.1 头声明</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-5-2_FixedRecyclerView"><span class="nav-number">3.5.2.</span> <span class="nav-text">2.5.2 FixedRecyclerView</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-5-3_ProgressWheel"><span class="nav-number">3.5.3.</span> <span class="nav-text">2.5.3 ProgressWheel</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-5-4_Toolbar_u9634_u5F71"><span class="nav-number">3.5.4.</span> <span class="nav-text">2.5.4 Toolbar阴影</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-5-5_BetterFab"><span class="nav-number">3.5.5.</span> <span class="nav-text">2.5.5 BetterFab</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-5-6__u62BD_u5C49_u4E2D_u7684ListView"><span class="nav-number">3.5.6.</span> <span class="nav-text">2.5.6 抽屉中的ListView</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-6_NotesAdapter"><span class="nav-number">3.6.</span> <span class="nav-text">2.6 NotesAdapter</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#2-6-1__u627F_u63A5_u5173_u7CFB"><span class="nav-number">3.6.1.</span> <span class="nav-text">2.6.1 承接关系</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#2-6-1-1_BaseRecyclerViewAdapter"><span class="nav-number">3.6.1.1.</span> <span class="nav-text">2.6.1.1 BaseRecyclerViewAdapter</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#2-6-1-1-1__u589E_u5220_u6539_u65B9_u6CD5"><span class="nav-number">3.6.1.1.1.</span> <span class="nav-text">2.6.1.1.1 增删改方法</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#2-6-1-1-2__u5185_u90E8_u70B9_u51FB_u4E8B_u4EF6"><span class="nav-number">3.6.1.1.2.</span> <span class="nav-text">2.6.1.1.2 内部点击事件</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#2-6-1-1-3__u52A8_u753B_u6548_u679C"><span class="nav-number">3.6.1.1.3.</span> <span class="nav-text">2.6.1.1.3 动画效果</span></a></li></ol></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-6-2_onCreateViewHolder"><span class="nav-number">3.6.2.</span> <span class="nav-text">2.6.2 onCreateViewHolder</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#2-6-2-1_NotesItemViewHolder"><span class="nav-number">3.6.2.1.</span> <span class="nav-text">2.6.2.1 NotesItemViewHolder</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-6-3__u7ED1_u5B9AViewHolder"><span class="nav-number">3.6.3.</span> <span class="nav-text">2.6.3 绑定ViewHolder</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-6-4__u8FC7_u6EE4_u64CD_u4F5C"><span class="nav-number">3.6.4.</span> <span class="nav-text">2.6.4 过滤操作</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-7_DrawerView_u7684_u521D_u59CB_u5316"><span class="nav-number">3.7.</span> <span class="nav-text">2.7 DrawerView的初始化</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#2-7-1_DrawerListAdapter"><span class="nav-number">3.7.1.</span> <span class="nav-text">2.7.1 DrawerListAdapter</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#2-7-1-1_BaseListAdapter"><span class="nav-number">3.7.1.1.</span> <span class="nav-text">2.7.1.1 BaseListAdapter</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-7-1-2_SimpleListAdapter"><span class="nav-number">3.7.1.2.</span> <span class="nav-text">2.7.1.2 SimpleListAdapter</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-7-1-3_DrawerListAdapter"><span class="nav-number">3.7.1.3.</span> <span class="nav-text">2.7.1.3 DrawerListAdapter</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#2-7-1-3-1__u5E03_u5C40"><span class="nav-number">3.7.1.3.1.</span> <span class="nav-text">2.7.1.3.1 布局</span></a></li></ol></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-7-2__u62BD_u5C49_u5F00_u5173_u6309_u94AE"><span class="nav-number">3.7.2.</span> <span class="nav-text">2.7.2 抽屉开关按钮</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-7-3__u8BBE_u7F6E_u62BD_u5C49_u906E_u5E18_u989C_u8272"><span class="nav-number">3.7.3.</span> <span class="nav-text">2.7.3 设置抽屉遮帘颜色</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-8_PopupMenu"><span class="nav-number">3.8.</span> <span class="nav-text">2.8 PopupMenu</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-9_ActionBar_u4E0A_u7684_u641C_u7D22_u6846"><span class="nav-number">3.9.</span> <span class="nav-text">2.9 ActionBar上的搜索框</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#2-9-1__u5B9A_u4E49_u83DC_u5355"><span class="nav-number">3.9.1.</span> <span class="nav-text">2.9.1 定义菜单</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-9-2__u521D_u59CB_u5316SearchView"><span class="nav-number">3.9.2.</span> <span class="nav-text">2.9.2 初始化SearchView</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-10__u5904_u7406_u83DC_u5355_u4E8B_u4EF6"><span class="nav-number">3.10.</span> <span class="nav-text">2.10 处理菜单事件</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-11__u5904_u7406_u5B9E_u4F53_u6309_u952E_u4E8B_u4EF6"><span class="nav-number">3.11.</span> <span class="nav-text">2.11 处理实体按键事件</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-12__u5220_u9664_u5BF9_u8BDD_u6846_u7684_u663E_u793A"><span class="nav-number">3.12.</span> <span class="nav-text">2.12 删除对话框的显示</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-13_SnackbarUtils"><span class="nav-number">3.13.</span> <span class="nav-text">2.13 SnackbarUtils</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#3-_Presenter__u2014_u2014_MVP_u4E2D_u7684_u6865_u6881"><span class="nav-number">4.</span> <span class="nav-text">3. Presenter —— MVP中的桥梁</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#3-1__u63A5_u53E3"><span class="nav-number">4.1.</span> <span class="nav-text">3.1 接口</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3-2__u6784_u9020_u51FD_u6570"><span class="nav-number">4.2.</span> <span class="nav-text">3.2 构造函数</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#3-2-1_Java_Annotation_u81EA_u5B9A_u4E49_u6CE8_u89E3"><span class="nav-number">4.2.1.</span> <span class="nav-text">3.2.1 Java Annotation自定义注解</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#3-2-1-1_Annotation_u6982_u8FF0"><span class="nav-number">4.2.1.1.</span> <span class="nav-text">3.2.1.1 Annotation概述</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-2-1-2__u5B9A_u4E49Annotation"><span class="nav-number">4.2.1.2.</span> <span class="nav-text">3.2.1.2 定义Annotation</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-2-1-3__u5143_u6CE8_u89E3"><span class="nav-number">4.2.1.3.</span> <span class="nav-text">3.2.1.3 元注解</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-2-1-4__u81EA_u5B9A_u4E49_u6CE8_u89E3"><span class="nav-number">4.2.1.4.</span> <span class="nav-text">3.2.1.4 自定义注解</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-2-1-5__u5BF9_u9879_u76EE_u4E2D_u201DContextLifeCycle_u201D_u7684_u5206_u6790"><span class="nav-number">4.2.1.5.</span> <span class="nav-text">3.2.1.5 对项目中”ContextLifeCycle”的分析</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-2-2_FinalDb_u53C2_u6570"><span class="nav-number">4.2.2.</span> <span class="nav-text">3.2.2 FinalDb参数</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#3-2-2-1__u6570_u636E_u5E93_u8FDE_u63A5_u6C60"><span class="nav-number">4.2.2.1.</span> <span class="nav-text">3.2.2.1 数据库连接池</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#3-2-2-1-1__u6570_u636E_u5E93_u4FE1_u606F_u914D_u7F6E_u7C7BDaoConfig"><span class="nav-number">4.2.2.1.1.</span> <span class="nav-text">3.2.2.1.1 数据库信息配置类DaoConfig</span></a></li></ol></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-2-2-2__u6784_u9020_u51FD_u6570"><span class="nav-number">4.2.2.2.</span> <span class="nav-text">3.2.2.2 构造函数</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#3-2-2-2-1_createDbFileOnSDCard_u65B9_u6CD5"><span class="nav-number">4.2.2.2.1.</span> <span class="nav-text">3.2.2.2.1 createDbFileOnSDCard方法</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#3-2-2-2-2_SqliteDbHelper_u5185_u90E8_u7C7B"><span class="nav-number">4.2.2.2.2.</span> <span class="nav-text">3.2.2.2.2 SqliteDbHelper内部类</span></a></li></ol></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-2-2-3__u516C_u6709_u7684create_28_29_u65B9_u6CD5"><span class="nav-number">4.2.2.3.</span> <span class="nav-text">3.2.2.3 公有的create()方法</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-2-2-4__u7528_u6CD5"><span class="nav-number">4.2.2.4.</span> <span class="nav-text">3.2.2.4 用法</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-2-3_PreferenceUtils_u53C2_u6570"><span class="nav-number">4.2.3.</span> <span class="nav-text">3.2.3 PreferenceUtils参数</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-2-4_ObservableUtils_u53C2_u6570"><span class="nav-number">4.2.4.</span> <span class="nav-text">3.2.4 ObservableUtils参数</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#3-2-4-1_Fun_u63A5_u53E3"><span class="nav-number">4.2.4.1.</span> <span class="nav-text">3.2.4.1 Fun接口</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-2-5_EverNoteUtils_u53C2_u6570"><span class="nav-number">4.2.5.</span> <span class="nav-text">3.2.5 EverNoteUtils参数</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3-3_onCreate_28_29_u65B9_u6CD5"><span class="nav-number">4.3.</span> <span class="nav-text">3.3 onCreate()方法</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#3-3-1_Activity_u5D29_u6E83_u7684_u4FE1_u606F_u4FDD_u5B58"><span class="nav-number">4.3.1.</span> <span class="nav-text">3.3.1 Activity崩溃的信息保存</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-3-2__u521D_u59CB_u5316_u89C6_u56FE"><span class="nav-number">4.3.2.</span> <span class="nav-text">3.3.2 初始化视图</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#3-3-2-1_initToolbar"><span class="nav-number">4.3.2.1.</span> <span class="nav-text">3.3.2.1 initToolbar</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-3-2-2__u521D_u59CB_u5316_u62BD_u5C49"><span class="nav-number">4.3.2.2.</span> <span class="nav-text">3.3.2.2 初始化抽屉</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-3-2-3__u8BBE_u7F6E_u62BD_u5C49_u65B9_u5411"><span class="nav-number">4.3.2.3.</span> <span class="nav-text">3.3.2.3 设置抽屉方向</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-3-2-4__u8BBE_u7F6ERecyclerView_u7EBF_u6027_u6216_u7F51_u683C_u6392_u5217"><span class="nav-number">4.3.2.4.</span> <span class="nav-text">3.3.2.4 设置RecyclerView线性或网格排列</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-3-2-5__u52A0_u8F7D_u7B14_u8BB0"><span class="nav-number">4.3.2.5.</span> <span class="nav-text">3.3.2.5 加载笔记</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#3-3-2-5-1_getLocalNotesByType"><span class="nav-number">4.3.2.5.1.</span> <span class="nav-text">3.3.2.5.1 getLocalNotesByType</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#3-3-2-5-2__u6307_u5B9A_u7EBF_u7A0B"><span class="nav-number">4.3.2.5.2.</span> <span class="nav-text">3.3.2.5.2 指定线程</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#3-3-2-5-3__u8BA2_u9605"><span class="nav-number">4.3.2.5.3.</span> <span class="nav-text">3.3.2.5.3 订阅</span></a></li></ol></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-3-3_EventBus_u5E93"><span class="nav-number">4.3.3.</span> <span class="nav-text">3.3.3 EventBus库</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#3-3-3-1__u4ECB_u7ECD"><span class="nav-number">4.3.3.1.</span> <span class="nav-text">3.3.3.1 介绍</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-3-3-2__u4F7F_u7528"><span class="nav-number">4.3.3.2.</span> <span class="nav-text">3.3.3.2 使用</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-3-3-3_4_u79CD_u63A5_u6536_u6D88_u606F_u65B9_u6CD5"><span class="nav-number">4.3.3.3.</span> <span class="nav-text">3.3.3.3 4种接收消息方法</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-3-3-3__u672C_u9879_u76EE_u4E2DEventBus_u4F7F_u7528"><span class="nav-number">4.3.3.4.</span> <span class="nav-text">3.3.3.3 本项目中EventBus使用</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-3-3-3-1__u6CE8_u518C_u4E0E_u53CD_u6CE8_u518C"><span class="nav-number">4.3.3.5.</span> <span class="nav-text">3.3.3.3.1 注册与反注册</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-3-3-3-2__u6D88_u606F_u63A5_u6536_u2014_u2014_u540C_u6B65_u7B14_u8BB0"><span class="nav-number">4.3.3.6.</span> <span class="nav-text">3.3.3.3.2 消息接收——同步笔记</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-3-3-3-3__u6D88_u606F_u63A5_u6536_u2014_u2014_u5176_u4ED6_u64CD_u4F5C"><span class="nav-number">4.3.3.7.</span> <span class="nav-text">3.3.3.3.3 消息接收——其他操作</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3-4_onResume_28_29"><span class="nav-number">4.4.</span> <span class="nav-text">3.4 onResume()</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3-5__u8FD4_u56DE_u76D1_u542C"><span class="nav-number">4.5.</span> <span class="nav-text">3.5 返回监听</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3-6__u540C_u6B65_u7B14_u8BB0"><span class="nav-number">4.6.</span> <span class="nav-text">3.6 同步笔记</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3-6__u542F_u52A8_u5176_u5B83Activity"><span class="nav-number">4.7.</span> <span class="nav-text">3.6 启动其它Activity</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#4-__u7B14_u8BB0_u7F16_u8F91_u754C_u9762"><span class="nav-number">5.</span> <span class="nav-text">4. 笔记编辑界面</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#4-1__u754C_u9762_u521D_u59CB_u5316"><span class="nav-number">5.1.</span> <span class="nav-text">4.1 界面初始化</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#4-2__u5E03_u5C40_u6587_u4EF6"><span class="nav-number">5.2.</span> <span class="nav-text">4.2 布局文件</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#4-3__u83DC_u5355_u7BA1_u7406"><span class="nav-number">5.3.</span> <span class="nav-text">4.3 菜单管理</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#4-3-1__u52A8_u6001_u4FEE_u6539_u83DC_u5355"><span class="nav-number">5.3.1.</span> <span class="nav-text">4.3.1 动态修改菜单</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#4-4__u521D_u59CB_u5316_u89C6_u56FE"><span class="nav-number">5.4.</span> <span class="nav-text">4.4 初始化视图</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#4-4-1__u7126_u70B9_u8BF7_u6C42"><span class="nav-number">5.4.1.</span> <span class="nav-text">4.4.1 焦点请求</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-4-2__u76D1_u542C_u5668"><span class="nav-number">5.4.2.</span> <span class="nav-text">4.4.2 监听器</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#4-5__u66F4_u591A_u7EC6_u8282"><span class="nav-number">5.5.</span> <span class="nav-text">4.5 更多细节</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#4-5-1__u952E_u76D8_u663E_u793A_u4E0E_u9690_u85CF"><span class="nav-number">5.5.1.</span> <span class="nav-text">4.5.1 键盘显示与隐藏</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-5-2__u63D0_u793A_u7528_u6237_u4FDD_u5B58"><span class="nav-number">5.5.2.</span> <span class="nav-text">4.5.2 提示用户保存</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#4-6_NotePresenter"><span class="nav-number">5.6.</span> <span class="nav-text">4.6 NotePresenter</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#4-6-1__u5B64_u6CE8_u4E00_u63B7"><span class="nav-number">5.6.1.</span> <span class="nav-text">4.6.1 孤注一掷</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-6-2__u4FDD_u5B58_u7B14_u8BB0"><span class="nav-number">5.6.2.</span> <span class="nav-text">4.6.2 保存笔记</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-6-3__u65F6_u95F4_u7684_u683C_u5F0F_u5316"><span class="nav-number">5.6.3.</span> <span class="nav-text">4.6.3 时间的格式化</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#4-6-3-1_TimeUtils"><span class="nav-number">5.6.3.1.</span> <span class="nav-text">4.6.3.1 TimeUtils</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-6-4__u4FDD_u5B58_u6309_u94AE_u7684_u9690_u73B0"><span class="nav-number">5.6.4.</span> <span class="nav-text">4.6.4 保存按钮的隐现</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#5-__u8BBE_u7F6E_u754C_u9762"><span class="nav-number">6.</span> <span class="nav-text">5. 设置界面</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#5-1__u521D_u59CB_u5316_u89C6_u56FE"><span class="nav-number">6.1.</span> <span class="nav-text">5.1 初始化视图</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#5-1-1__u788E_u7247"><span class="nav-number">6.1.1.</span> <span class="nav-text">5.1.1 碎片</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#5-1-1-1__u627F_u63A5_u5173_u7CFB"><span class="nav-number">6.1.1.1.</span> <span class="nav-text">5.1.1.1 承接关系</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#5-1-1-2__u7ED1_u5B9AActivity"><span class="nav-number">6.1.1.2.</span> <span class="nav-text">5.1.1.2 绑定Activity</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#5-1-1-3__u8BBE_u7F6E_u9879_u521D_u59CB_u5316"><span class="nav-number">6.1.1.3.</span> <span class="nav-text">5.1.1.3 设置项初始化</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#5-1-1-3-1_PreferenceScreen"><span class="nav-number">6.1.1.3.1.</span> <span class="nav-text">5.1.1.3.1 PreferenceScreen</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#5-1-1-3-2__u8BBE_u5B9A_u6587_u4EF6"><span class="nav-number">6.1.1.3.2.</span> <span class="nav-text">5.1.1.3.2 设定文件</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#5-1-1-3-3_Presenter"><span class="nav-number">6.1.1.3.3.</span> <span class="nav-text">5.1.1.3.3 Presenter</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#5-1-1-3-4_findPreference"><span class="nav-number">6.1.1.3.4.</span> <span class="nav-text">5.1.1.3.4 findPreference</span></a></li></ol></li><li class="nav-item nav-level-4"><a class="nav-link" href="#5-1-1-4__u5BF9_u5916_u63D0_u4F9B_u65B9_u6CD5"><span class="nav-number">6.1.1.4.</span> <span class="nav-text">5.1.1.4 对外提供方法</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#5-1-1-5_ListView_u81EA_u5B9A_u4E49"><span class="nav-number">6.1.1.5.</span> <span class="nav-text">5.1.1.5 ListView自定义</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#5-2__u4E3B_u9898_u5207_u6362_u5BF9_u8BDD_u6846"><span class="nav-number">6.2.</span> <span class="nav-text">5.2 主题切换对话框</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#5-2-1__u4E3B_u9898_u989C_u8272_u5B50_u9879"><span class="nav-number">6.2.1.</span> <span class="nav-text">5.2.1 主题颜色子项</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#5-2-2__u7F51_u683C_u89C6_u56FE"><span class="nav-number">6.2.2.</span> <span class="nav-text">5.2.2 网格视图</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#5-2-3__u70B9_u51FB_u4E8B_u4EF6"><span class="nav-number">6.2.3.</span> <span class="nav-text">5.2.3 点击事件</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#5-3_SettingPresenter"><span class="nav-number">6.3.</span> <span class="nav-text">5.3 SettingPresenter</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#5-3-1_onCreate_28_29"><span class="nav-number">6.3.1.</span> <span class="nav-text">5.3.1 onCreate()</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#5-3-2__u90AE_u4EF6_u53D1_u9001"><span class="nav-number">6.3.2.</span> <span class="nav-text">5.3.2 邮件发送</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#5-3-3__u5907_u4EFD_u7B14_u8BB0"><span class="nav-number">6.3.3.</span> <span class="nav-text">5.3.3 备份笔记</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#5-3-4__u5E94_u7528_u8BC4_u5206"><span class="nav-number">6.3.4.</span> <span class="nav-text">5.3.4 应用评分</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#5-3-5__u6253_u8D4F_u6A21_u5757"><span class="nav-number">6.3.5.</span> <span class="nav-text">5.3.5 打赏模块</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#6-_AboutActivity"><span class="nav-number">7.</span> <span class="nav-text">6. AboutActivity</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#6-1__u521D_u59CB_u5316_u89C6_u56FE"><span class="nav-number">7.1.</span> <span class="nav-text">6.1 初始化视图</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#6-1-1__u5E03_u5C40_u6587_u4EF6"><span class="nav-number">7.1.1.</span> <span class="nav-text">6.1.1 布局文件</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#6-1-2__u7248_u672C_u4FE1_u606F"><span class="nav-number">7.1.2.</span> <span class="nav-text">6.1.2 版本信息</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#6-1-3__u8FDE_u7EED_u6572_u51FB_u5F69_u86CB"><span class="nav-number">7.1.3.</span> <span class="nav-text">6.1.3 连续敲击彩蛋</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#6-2__u5206_u4EAB_u5BF9_u8BDD_u6846"><span class="nav-number">7.2.</span> <span class="nav-text">6.2 分享对话框</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#u603B_u7ED3"><span class="nav-number">8.</span> <span class="nav-text">总结</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#u53C2_u8003"><span class="nav-number">9.</span> <span class="nav-text">参考</span></a></li></ol></div>
            

          </div>
        </section>
      <!--/noindex-->
      

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright">&copy; 2015 &mdash; <span itemprop="copyrightYear">2017</span>
  <span class="with-love">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">WuHaojie</span>

  
</div>









        







        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  


  











  
  <script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script>

  
  <script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>

  
  <script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>

  
  <script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script>

  
  <script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>

  
  <script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>

  
  <script type="text/javascript" src="/lib/canvas-nest/canvas-nest.min.js"></script>


  


  <script type="text/javascript" src="/js/src/utils.js?v=5.1.3"></script>

  <script type="text/javascript" src="/js/src/motion.js?v=5.1.3"></script>



  
  

  
  <script type="text/javascript" src="/js/src/scrollspy.js?v=5.1.3"></script>
<script type="text/javascript" src="/js/src/post-details.js?v=5.1.3"></script>



  


  <script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.3"></script>



  


  




	





  





  








  





  

  

  

  

  

  

</body>
</html>
